
#+TITLE: Git Deep Dive

#+SUBTITLE: [[file:{{{input-file}}}?print-pdf][Printable version]]

#+DATE: <2018-06-25 Mon>
#+AUTHOR: Éibhear Ó hAnluain
#+EMAIL: eibhear.geo@gmail.com

#+OPTIONS: ':nil *:t -:t ::t <:t \n:nil ^:{} author:t c:nil creator:nil
#+OPTIONS: d:nil date:t e:t email:t f:t inline:t num:nil p:nil pri:nil
#+OPTIONS: stat:nil tags:nil tasks:t tex:t timestamp:nil toc:1 todo:nil |:t
#+DESCRIPTION: A journey into the depths of git
#+LANGUAGE: en

# <Where the reveal.js project (https://github.com/hakimel/reveal.js.git) is cloned/copied to>
#+REVEAL_ROOT: ../reveal.js

# Possible transitions: default (like a sphere!), cube, page, concave, zoom, linear, fade, none
#+REVEAL_INIT_OPTIONS: transition:'concave', margin: 0.1, slideNumber:true

# Possible themes: beige, black, blood, league, moon, night, serif, simple, sky, solarized, white
#+REVEAL_THEME: white

#+REVEAL_HLEVEL: 1

# <Copy this file to where the generated HTML will be>
#+REVEAL_EXTRA_CSS: ./styles/e-reveal.css
#+REVEAL_EXTRA_CSS: ./styles/gridding.css

# <Copy this file to where the generated HTML will be>
#+REVEAL_DEFAULT_SLIDE_BACKGROUND: ./images/bCardBackground.png
#+REVEAL_TITLE_SLIDE_BACKGROUND: ./images/bCardBackground.png
#+REVEAL_TOC_SLIDE_BACKGROUND: ./images/bCardBackground.png

#+REVEAL_DEFAULT_SLIDE_SIZE: 100%
#+REVEAL_TITLE_SLIDE_SIZE: 100%
#+REVEAL_TOC_SLIDE_SIZE: 100%

* Synopsis                                                         :noexport:

  *Git Deep Dive*

  So.

  You've cloned.

  You've pulled, and you've pushed.

  You've branched, merged and resolved conflicts.

  You may even have fetched and pruned.

  You're empowered to use git as a developer, and as a team lead.

  But...

  Have you ever peaked under the bonnet?

  What makes up a commit? What exactly is meant when we say git stores
  changes as snapshots? Why is git sometimes called a
  "content-addressable filesystem"? Why does that matter? What's the
  difference between "porcelain" and "plumbing"?

  This "git Deep Dive" will start off revising what developers do on a
  normal day-to-day basis, but will quickly slip under the surface to
  explore the different layers of a git repository, and show you the
  tools to explore the shallows, the continental shelves, and the deep
  trenches that hide beneath the surface of the standard developer
  tooling.

  As you emerge from this technology meet-up, awed and blinking in the
  summer sun, you'll come away knowing some small nuggets of how to
  solve some of the more interesting problems that you might come
  across, but also knowing what's out there to help with that one
  problem that will make you the git guru of your team.

* Introduction
** Introduction
   Assumes basic knowledge: =clone=, =add=, =commit=, =merge=, =pull=, =push=

   Assumes comfort with the command line: =git= on Linux; =git bash=, =git cmd= on Windows

   - Paddling :: config, fetch-and-merge, merge approaches
   - Snorkling and Scuba diving :: refs, =HEAD=, annotated tags, submodules, =blame=, signing and verifying commits
   - Submarining :: the structure of a commit, "Content Addressable Filesystem", git objects
   - Unmanned submersibles :: the reflog, =fsck= and =gc=, finding and dealing with specific git objects
** About Éibhear Ó hAnluain
   - Solutions Architect
     + eibhear.geo@gmail.com
   - Software engineer since 1994
   - Using revision control since 1994: _subversion_, _git_,
     _IBM/Rational/Atria ClearCase_, _RCS_, _VSS_, _CVS_, _Serena
     SCM_, _Serena PVCS_, _SCCS_
   - Introduced revision control in multiple environments
   - Multiple revision-control migrations
     + RCS -> subversion
     + VSS -> subversion
     + CVS -> git
* The Coast
  #+CAPTION: By Frédéric de Goldschmidt www.frederic.net - Own work, CC BY 3.0, https://commons.wikimedia.org/w/index.php?curid=3972438
  file:./images/Grotta_azzurra.jpg
  
** Configuration
   - Precedence: local (default), global, system, defaulted.
     #+BEGIN_SRC  shell
       git config --local --list
       git config --global --list
       git config --system --list
       git config [--system|--global|--local] <key> <value>
       git config -e
     #+END_SRC
** =fetch= and =merge=, not =pull=
   - "=git pull= is just =git fetch= and then =git merge="
   - When should you use =git pull=? When...
     1. ... there are no local changes to be committed or pushed; and
     2. you know the changes =pull= will make.
   - Why?: =pull= doesn't stop to let you review the merged-in
     changes in case it didn't go well.
   - Suggestions:
     + =git fetch --prune= followed by =git diff= followed by =git merge=
     + =git pull --prune --no-commit= followed by =git commit=
       * Allows review before commit, but doesn't apply if merge is =fast-forward=
** =fetch= and =merge=, not =pull=
   Other suggestions
   - ~--prune~ :: Indicates the branches that have been removed from
     the remote, suggesing to you to remove the local branches
   - ~git branch -va~ :: Allows you to get a full view of the local
     and remote branches
** Merging approaches
   Merging, merging strategies
   - fast-forward :: where the tip commit of the target branch is a
     direct ancestor of the tip commit of the source branch. Merge is
     to re-locate the target branch label; no changes to files.
   - Merge :: to apply the changes done on the source branch onto the
     target branch

     _Strategies_
     + resolve
     + recursive
     + octopus
     + ours
     + subtree
   - rebase :: to replay the changes made onto one commit onto
     another.
** Merging approaches: fast-forward
   #+REVEAL_HTML: <div class="gridded_frame_with_columns">

   #+REVEAL_HTML: <div class="one_of_2_columns">
   #+ATTR_HTML: :width 70%
   file:./images/fast-forward-initial-state.png
   #+REVEAL_HTML: </div>

   #+REVEAL_HTML: <div class="one_of_2_columns">
   #+ATTR_REVEAL: :frag t
   #+ATTR_HTML: :width 85%
   file:./images/fast-forward-completed-state.png
   #+REVEAL_HTML: </div>

   #+REVEAL_HTML: </div>
** Merging approaches: merging strategies
   #+REVEAL_HTML: <div class="gridded_frame_with_columns">

   #+REVEAL_HTML: <div class="one_of_2_columns">
   Git automatically decides which strategy to use, but the user can
   also specify:
   - =recursive=: The default. For merging one branch into another,
     seeking to ensure previous merges are handled properly.
   - =resolve=: For merging one branch into another. Safe and fast.
   - =octopus=: For merging 3 or more branches.
   - =ours=: For dealing with old branches; preserves the state of the
     target branch
   - =subtree=: For merging trees that are at different levels.
   #+REVEAL_HTML: </div>

   #+REVEAL_HTML: <div class="one_of_2_columns">
   #+ATTR_HTML: :width 70%
   file:./images/two-branch-completed-state.png
   #+REVEAL_HTML: </div>

   #+REVEAL_HTML: </div>
** Merging approaches: Rebase
   #+REVEAL_HTML: <div class="gridded_frame_with_columns">

   #+REVEAL_HTML: <div class="one_of_2_columns">
   #+ATTR_HTML: :width 70%
   file:./images/fast-forward-completed-state.png
   #+REVEAL_HTML: </div>

   #+REVEAL_HTML: <div class="one_of_2_columns">

   #+ATTR_REVEAL: :frag t
   #+ATTR_HTML: :width 40%
   file:./images/rebase-completed-state.png

   #+REVEAL_HTML: </div>

   #+REVEAL_HTML: </div>
** Merging appraoches: Decision tree
   file:./images/merge-decision-tree-chart.png
* The Shallows
** 
*** A little deeper                                           :B_block:BMCOL:
    :PROPERTIES:
    :BEAMER_col: 0.9
    :BEAMER_env: block
    :END:
     file:./images/Naufragio_por_Gustavo_Gerdel.jpg

#+latex: {\tiny
     By Ggerdel - Foto de: Gustavo Gerdel (BAB Buceo) [CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0)], via Wikimedia Commons
#+latex: }
** Refs
*** Refs
    - Branches
      #+BEGIN_SRC
      $ ls -1 .git/refs/heads/*
      .git/refs/heads/gitlab_10.x_upgrade
      .git/refs/heads/gitlab-ce-8.17
      .git/refs/heads/gitlab-ce-9.1.4-defectFix
      .git/refs/heads/master

      $ cat .git/refs/heads/gitlab-ce-8.17
      c63767d0b9b520f36a533237624dfaa1256b463c
      #+END_SRC
** Refs
*** Refs
    - tags
      #+BEGIN_SRC
      $ ls -1 .git/refs/tags/
      gitlab-cookbook-for-10.7.3
      gitlab-cookbook-initial
      gitlab-cookbook-rebaseline

      $ cat .git/refs/tags/gitlab-cookbook-for-10.7.3
      f16b12027cef7052e09f3a483ace55999800ea5b
      #+END_SRC
    - =HEAD=
      #+BEGIN_SRC
      $ cat .git/HEAD
      ref: refs/heads/gitlab_10.x_upgrade
      #+END_SRC
** Refs
*** Refs
    - remotes
      #+BEGIN_SRC
      $ ls -1 .git/refs/remotes/origin/*
      .git/refs/remotes/origin/ara_test
      .git/refs/remotes/origin/brjones_aci_network
      .git/refs/remotes/origin/gitlab_10.x_upgrade
      .git/refs/remotes/origin/gitlab-ce-8.17
      .git/refs/remotes/origin/gitlab-ce-9.1.4-defectFix
      .git/refs/remotes/origin/HEAD
      .git/refs/remotes/origin/master

      $ cat .git/refs/remotes/origin/ara_test
      7130b7ee374ad9f7ba784ec0b0d0b86dc99f41d4
      #+END_SRC
** HEAD
*** HEAD
    - =HEAD= is a ref that points to where the commit currently checked out
    - =HEAD= in a remote repository usually points to the default branch

    #+BEGIN_SRC
    $ cat .git/HEAD
    ref: refs/heads/master
    $ cat .git/refs/remotes/origin/HEAD
    ref: refs/remotes/origin/REL2_0
    #+END_SRC
** Annotated tags
*** Annotated tags
    - A normal tag is just a "ref", pointing to a commit.
      #+BEGIN_SRC shell
        git tag Rel1.0 Rel1
        cat .git/refs/tags/Rel1.0
        git cat-file -t $(cat .git/refs/tags/Rel1.0)
        git cat-file -p $(cat .git/refs/tags/Rel1.0)
      #+END_SRC
    - *Caveat*: tags and branches use different namespaces, so
      temptation to tag the =Rel1= branch with =Rel1= would be
      high. However, this causes confusion for many git tools, so
      should be avoided.
** Annotated tags
*** Annotated tags
    - An annotated tag is a separate git object, that records information specfic to the tag:
      + Tag name; date; tagger; commit it's pointing to
    - Advice is for annotated tags to be used for significant announcements/releases/snaphots.
      #+BEGIN_SRC shell
        git tag -a -m "Formal release of 1.0" \
            Rel1.0.prod Rel1
        cat .git/refs/tags/Rel1.0.prod
        git cat-file -t $(cat .git/refs/tags/Rel1.0.prod)
        git cat-file -p $(cat .git/refs/tags/Rel1.0.prod)
      #+END_SRC
** blame
*** =blame=
    - Identifies the commit, commit author and date for each line in a file.
    - Doesn't give information for lines that have been removed or replaced.
** Tag and commit signing
*** Tag and commit signing and verification
    - PGP/GnuPG (=gpg=): expects familiarity with public/private key encryption.
    - Sign tags and commits with private key to assure integrity
      #+BEGIN_SRC shell
        git commit -Seibhear.geo@gmail.com \
            -m "Update to information.md"
        git cat-file -p $(cat .git/refs/heads/master)
        git tag -s -u eibhear.geo@gmail.com \
            -m "Release 2." Rel2.0 Rel2
        git cat-file -p $(cat .git/refs/tags/Rel2.0)
      #+END_SRC
    - Verify commits and tags with public key
      #+BEGIN_SRC
      git tag -v Rel2.0
      git log --show-signature -1
      #+END_SRC
* The Continental shelf
** 
*** Switch on the Sonar                                       :B_block:BMCOL:
    :PROPERTIES:
    :BEAMER_col: 0.9
    :BEAMER_env: block
    :END:
     file:./images/Loligo_vulgaris.jpg

#+latex: {\tiny
     By © Hans Hillewaert, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=385705
#+latex: }
** Git Objects -- blobs
*** Blob (file)
    A file
    #+BEGIN_SRC shell
      $ cat ~/.profile | git hash-object --stdin
      c9db4591825bd7a918df686ff04aeb3a87d3bda0
    #+END_SRC
** Git Objects -- trees
*** Tree
    A listing of files and other tree objects containing the
    following information on each: access mode (similar to UNIX
    permissions); type (e.g. =tree=, =blob=); SHA1; file/directory
    name
    #+BEGIN_SRC shell
      $ git cat-file -p \
            2c4e4782bcb6b13a0e11b6961004dec8745e9d35
      040000 tree bcd2824258ddf007dae7f88da7d727fb3894691b
          Astro
      100644 blob 94aea57573b92d9188a3df4cf748b60efd968803
          MyHelloWorldBean.java
      100644 blob c55118d1afb2be6a6d0f728814c084d54e97db14
          MyHelloWorldServlet.java
    #+END_SRC
** Git Objects -- commits
*** Commit
    Information on a commit event:
    - The SHA1 of the top-level tree of the project.
    - The parent commit (or commits, if this commit is the result of
      a merge)
    - The details of the author of the code that is being applied
      with the commit (including date and time)
    - The details of the person who applied the commit (including date and time)
    - The commit gpg signature, if present
    - The commit comment
** Git Objects -- commits
*** Commit
    #+BEGIN_SRC shell
      $ git cat-file -p \
            37c5611a177c9eafbd17e4302b6d644434b1042b
      tree 40b6262f3f3f5fc8cb8a0c78ca558a683dfc2323
      parent 42608808a973b8e0c4a4b0105c2317d81b12851f
      parent 36d56f097ca81f06d77f46cbde3fc10cbf6639f9
      author Master O'Theuniverse \
          <master.otheuniverse@example.com> \
          1529840879 +0100
      committer Master O'Theuniverse \
          <master.otheuniverse@example.com> \
          1529840879 +0100

      REV18_5 now live
    #+END_SRC
** Git Objects -- tags
*** Tag
    A tag points to a commit object, and an annotated tag contains
    additional information
    - What object it's pointing at and its type
    - The name of the tag
    - Who applied the tag (including date and time)
    - A tag comment
** Git Objects -- tags
*** Tag
    #+BEGIN_SRC shell
      $ git cat-file -p \
            88a4c18867ccb1d7c398f285460d8abab3964e75
      object 66d8336c2770d0d1cea3dcb0175611edb5e69f69
      type commit
      tag Rel1.0.a
      tagger Éibhear Ó hAnluain \
          <eibhear.geo@gmail.com> \
          1529847749 +0100

      An annotated tag for the Rel1 release

      $ git cat-file -t \
            66d8336c2770d0d1cea3dcb0175611edb5e69f69
      commit
    #+END_SRC
** "Content Addressable Filesystem"
*** "Content Addressable Filesystem"
    As the IDs of objects are based on their contents, they are
    located in the git database according to that name
    #+BEGIN_SRC shell
      git rev-list --all --objects
      git cat-file -p \
          b5aea839bc89a0c7931af469ff9c145be18854d7
      git cat-file -p \
          b5aea839bc89a0c7931af469ff9c145be18854d7 | \
          git hash-object --stdin
      ls -l .git/objects/b5/aea839bc89a0c7931af469ff9c145be18854d7
    #+END_SRC
* The Deep trenches
** 
*** Exotic creatures                                          :B_block:BMCOL:
    :PROPERTIES:
    :BEAMER_col: 0.7
    :BEAMER_env: block
    :END:
     file:./images/Alvinella_pompejana01.jpg

#+latex: {\tiny
     By National Science Foundation (University of Delaware College of Marine Studies) - http://www.nsf.gov/od/lpa/news/press/01/pr0190.htm, Public Domain, https://commons.wikimedia.org/w/index.php?curid=7123122
#+latex: }
** The reflog
*** The reflog
    - A log of all the changes to HEAD
    - Local only: not involved in pulls, pushes or fetches.
    - Useful for recovering accidentally removed commits
    - Completely clear the reflog
      : git reflog expire --expire=now \
      :     --expire-unreachable=now --verbose --all
** fsck and gc
*** fsck and gc
    - fsck :: Analyse connectivity of the objects in the git
              database. Useful for finding objects that aren't of any
              use any more.
    - gc :: "Garbage collector". Compress and pack objects, remove
            "danlging" and unreachable objects
** Useful commands
*** Useful commands
    - Find the largest object in your git database
      #+BEGIN_SRC shell
        git cat-file \
            --batch-check='%(objecttype) %(objectname) %(objectsize)' \
            --batch-all-objects | sed -n 's/^blob //p' | \
            sort -n --key=2
      #+END_SRC
    - List all objects in your git database
      : git rev-list --all --objects
    - Determine the filename related to a blob object
      : git rev-list --objects --all | grep <objectID>
    - Determine commits that reference that file
      : git log --follow -- "<fileNameAndPath>"
** Permanently removing a file from your git db
*** Permanently removing a file from your git db
    - e.g. contains password information, v. large file not required, etc.
    - For each branch...
      + Check it out
        : git checkout <branch>
      + Remove the file from all commits
        #+BEGIN_SRC shell
          git filter-branch --tree-filter \
              'rm -f <filePathAndName>' \
              --prune-empty HEAD
        #+END_SRC
      + Clean up the original refs
        #+BEGIN_SRC shell
          git for-each-ref --format="%(refname)" \
              refs/original/ | \
              xargs -n 1 git update-ref -d
        #+END_SRC
** Permanently removing a file from your git db
*** Permanently removing a file from your git db
    - ... then ...
      - Clear out the reflog
        : git reflog expire --expire-unreachable=now --all
        The reflog maintains references to commits and objects you
        may want to remove.
      - Collect the garbage, regardless of age
        : git gc --prune=now
      - Sanity-check all objects
        : git fsck --unreachable --no-reflogs
** Other interesting concepts
*** Other interesting concepts
    - *Porcelain vs Plumbing*: The commands that we use vs the commands that *they* use.
      + *Porcelain*: =init=, =clone=, =fetch=, =push=, =add=, =commit=, etc.
      + *Plumbing*: =hash-object=, =cat-file=, =write-tree=, =count-objects=, etc.
    - *submodules*: to link a separate git repository into yours
    - *fast-import*: to import data into a git repository from other,
      non-git sources (e.g. cvs, subversion, etc.)
** Resources
*** Resources
    - The git book :: https://git-scm.com/book/en/v2/
    - The git manual ::
                        #+BEGIN_SRC shell
                          git help --all
                          git help merge
                          git help cat-file
                          man git-hash-object
                        #+END_SRC
    - Stack overflow :: https://stackoverflow.com/questions/tagged/git
* Commands                                                         :noexport:
  |   | add                      |
  |   | add--interactive         |
  |   | am                       |
  | x | +annotate+               |
  |   | apply                    |
  |   | archive                  |
  |   | bisect                   |
  |   | bisect--helper           |
  | + | blame                    |
  |   | branch                   |
  |   | bundle                   |
  |   | cat-file                 |
  |   | check-attr               |
  |   | check-ignore             |
  |   | check-mailmap            |
  |   | check-ref-format         |
  |   | checkout                 |
  |   | checkout-index           |
  |   | cherry                   |
  |   | cherry-pick              |
  |   | clean                    |
  |   | clone                    |
  |   | column                   |
  |   | commit                   |
  |   | commit-tree              |
  | + | config                   |
  |   | count-objects            |
  |   | credential               |
  |   | credential-cache         |
  |   | credential-cache--daemon |
  |   | credential-store         |
  |   | daemon                   |
  |   | describe                 |
  |   | diff                     |
  |   | diff-files               |
  |   | diff-index               |
  |   | diff-tree                |
  |   | difftool                 |
  |   | difftool--helper         |
  | + | fast-export              |
  | + | fast-import              |
  |   | fetch                    |
  |   | fetch-pack               |
  | + | filter-branch            |
  |   | fmt-merge-msg            |
  |   | for-each-ref             |
  |   | format-patch             |
  | + | fsck                     |
  | + | fsck-objects             |
  | + | gc                       |
  |   | get-tar-commit-id        |
  |   | grep                     |
  |   | hash-object              |
  |   | help                     |
  |   | http-backend             |
  |   | http-fetch               |
  |   | http-push                |
  |   | imap-send                |
  |   | index-pack               |
  |   | init                     |
  |   | init-db                  |
  |   | instaweb                 |
  |   | log                      |
  |   | ls-files                 |
  | + | ls-remote                |
  |   | ls-tree                  |
  |   | mailinfo                 |
  |   | mailsplit                |
  |   | merge                    |
  |   | merge-base               |
  |   | merge-file               |
  |   | merge-index              |
  |   | merge-octopus            |
  |   | merge-one-file           |
  |   | merge-ours               |
  |   | merge-recursive          |
  |   | merge-resolve            |
  |   | merge-subtree            |
  |   | merge-tree               |
  |   | mergetool                |
  |   | mktag                    |
  | x | +mktree+                 |
  |   | mv                       |
  |   | name-rev                 |
  |   | notes                    |
  | + | pack-objects             |
  |   | pack-redundant           |
  |   | pack-refs                |
  |   | patch-id                 |
  |   | prune                    |
  |   | prune-packed             |
  |   | pull                     |
  |   | push                     |
  |   | quiltimport              |
  |   | read-tree                |
  | + | rebase                   |
  |   | receive-pack             |
  |   | reflog                   |
  |   | relink                   |
  |   | remote                   |
  |   | remote-ext               |
  |   | remote-fd                |
  |   | remote-ftp               |
  |   | remote-ftps              |
  |   | remote-http              |
  |   | remote-https             |
  |   | remote-testsvn           |
  |   | repack                   |
  |   | replace                  |
  |   | request-pull             |
  | ? | rerere                   |
  |   | reset                    |
  |   | rev-list                 |
  |   | rev-parse                |
  |   | revert                   |
  |   | rm                       |
  |   | send-pack                |
  |   | sh-i18n--envsubst        |
  | x | +shell+                  |
  |   | shortlog                 |
  |   | show                     |
  |   | show-branch              |
  |   | show-index               |
  |   | show-ref                 |
  |   | stage                    |
  |   | stash                    |
  |   | status                   |
  |   | stripspace               |
  | + | submodule                |
  |   | subtree                  |
  |   | svn                      |
  |   | symbolic-ref             |
  |   | tag                      |
  |   | unpack-file              |
  |   | unpack-objects           |
  |   | update-index             |
  |   | update-ref               |
  |   | update-server-info       |
  |   | upload-archive           |
  |   | upload-pack              |
  |   | var                      |
  |   | verify-commit            |
  |   | verify-pack              |
  |   | verify-tag               |
  |   | web--browse              |
  |   | whatchanged              |
  |   | write-tree               |

* Diagrams                                                         :noexport:
** Diagram builder
   #+name: rev-control-flow-builder
   #+BEGIN_SRC emacs-lisp :results raw :colnames yes :var legend=rev-control-flow-legend nodes=rev-control-flow-elements graph=rev-control-flow-connections ranks=rev-control-flow-ranks
     (org-dot-flow-chart nodes graph ranks legend nil)
   #+END_SRC

   #+RESULTS: rev-control-flow

*** Flow legend
    #+name: rev-control-flow-legend
    | *node* | *label* | *colour* |
    |--------+---------+----------|
*** Flow elements
    #+name: rev-control-flow-elements
    | *node*  | *label* | *shape*   | *fillcolor* | *style* |
    |---------+---------+-----------+-------------+---------|
*** Flow connections
    #+name: rev-control-flow-connections
    | from    | to      | label | colour | style |
    |---------+---------+-------+--------+-------|
*** Flow ranks
    #+name: rev-control-flow-ranks
    | anchor  | node   |
    |---------+--------|

** Fast forward merge initial state diagram
   #+name: fast-forward-initial-state-chart
   #+BEGIN_SRC dot :file ./fast-forward-initial-state.png :var code=rev-control-flow-builder(legend=ff-initial-legend,nodes=ff-initial-elements,graph=ff-initial-connections,ranks=ff-initial-ranks)
   $code
   #+END_SRC

   #+RESULTS: fast-forward-initial-state-chart
   [[file:./images/fast-forward-initial-state.png]]

*** Flow legend
    #+name: ff-initial-legend
    | *node* | *label* | *colour* |
    |--------+---------+----------|
*** Flow elements
    #+name: ff-initial-elements
    | *node*  | *label* | *shape*   | *fillcolor* | *style* |
    |---------+---------+-----------+-------------+---------|
    | commit1 | a8ebfae | circle    | green       |         |
    | commit2 | 21ab34c | circle    | green       |         |
    | commit3 | 785cd72 | circle    | green       |         |
    | commit4 | f471562 | circle    | green       |         |
    | commit5 | a642864 | circle    | green       |         |
    | commit6 | 558628d | circle    | green       |         |
    | commit7 | a3b95aa | circle    | green       |         |
    | master  | master  | rectangle | yellow      |         |
    | rel1    | Rel1    | rectangle | yellow      |         |
    | rel2    | Rel2    | rectangle | yellow      |         |
    |---------+---------+-----------+-------------+---------|
*** Flow connections
    #+name: ff-initial-connections
    | from    | to      | label | colour | style |
    |---------+---------+-------+--------+-------|
    | commit2 | commit1 |       |        |       |
    | commit3 | commit2 |       |        |       |
    | commit4 | commit3 |       |        |       |
    | commit5 | commit4 |       |        |       |
    | commit6 | commit3 |       |        |       |
    | commit7 | commit6 |       |        |       |
    | master  | commit3 |       |        |       |
    | rel1    | commit5 |       |        |       |
    | rel2    | commit7 |       |        |       |
    |---------+---------+-------+--------+-------|
*** Flow ranks
    #+name: ff-initial-ranks
    | anchor  | node   |
    |---------+--------|
    | commit3 | master |
    | commit5 | rel1   |
    | commit7 | rel2   |
    |---------+--------|

** Fast forward merge completed state diagram
   #+name: fast-forward-completed-state-chart
   #+BEGIN_SRC dot :file ./fast-forward-completed-state.png :var code=rev-control-flow-builder(legend=ff-completed-legend,nodes=ff-completed-elements,graph=ff-completed-connections,ranks=ff-completed-ranks)
   $code
   #+END_SRC

   #+RESULTS: fast-forward-completed-state-chart
   [[file:./images/fast-forward-completed-state.png]]

*** Flow legend
    #+name: ff-completed-legend
    | *node* | *label* | *colour* |
    |--------+---------+----------|
*** Flow elements
    #+name: ff-completed-elements
    | *node*  | *label* | *shape*   | *fillcolor* | *style* |
    |---------+---------+-----------+-------------+---------|
    | commit1 | a8ebfae | circle    | green       |         |
    | commit2 | 21ab34c | circle    | green       |         |
    | commit3 | 785cd72 | circle    | green       |         |
    | commit4 | f471562 | circle    | green       |         |
    | commit5 | a642864 | circle    | green       |         |
    | commit6 | 558628d | circle    | green       |         |
    | commit7 | a3b95aa | circle    | green       |         |
    | master  | master  | rectangle | yellow      |         |
    | rel1    | Rel1    | rectangle | yellow      |         |
    | rel2    | Rel2    | rectangle | yellow      |         |
    |---------+---------+-----------+-------------+---------|
*** Flow connections
    #+name: ff-completed-connections
    | from    | to      | label | colour | style |
    |---------+---------+-------+--------+-------|
    | commit2 | commit1 |       |        |       |
    | commit3 | commit2 |       |        |       |
    | commit4 | commit3 |       |        |       |
    | commit5 | commit4 |       |        |       |
    | commit6 | commit3 |       |        |       |
    | commit7 | commit6 |       |        |       |
    | master  | commit5 |       |        |       |
    | rel1    | commit5 |       |        |       |
    | rel2    | commit7 |       |        |       |
    |---------+---------+-------+--------+-------|
*** Flow ranks
    #+name: ff-completed-ranks
    | anchor  | node   |
    |---------+--------|
    | commit5 | master |
    | commit5 | rel1   |
    | commit7 | rel2   |
    |---------+--------|

** Two-branch merge completed state diagram
   #+name: two-branch-completed-state-chart
   #+BEGIN_SRC dot :file ./two-branch-completed-state.png :var code=rev-control-flow-builder(legend=two-branch-completed-legend,nodes=two-branch-completed-elements,graph=two-branch-completed-connections,ranks=two-branch-completed-ranks)
   $code
   #+END_SRC

   #+RESULTS: two-branch-completed-state-chart
   [[file:./images/two-branch-completed-state.png]]

*** Flow legend
    #+name: two-branch-completed-legend
    | *node* | *label* | *colour* |
    |--------+---------+----------|
*** Flow elements
    #+name: two-branch-completed-elements
    | *node*  | *label* | *shape*   | *fillcolor* | *style* |
    |---------+---------+-----------+-------------+---------|
    | commit1 | a8ebfae | circle    | green       |         |
    | commit2 | 21ab34c | circle    | green       |         |
    | commit3 | 785cd72 | circle    | green       |         |
    | commit4 | f471562 | circle    | green       |         |
    | commit5 | a642864 | circle    | green       |         |
    | commit6 | 558628d | circle    | green       |         |
    | commit7 | a3b95aa | circle    | green       |         |
    | commit8 | f3ca059 | circle    | green       |         |
    | master  | master  | rectangle | yellow      |         |
    | rel1    | Rel1    | rectangle | yellow      |         |
    | rel2    | Rel2    | rectangle | yellow      |         |
    |---------+---------+-----------+-------------+---------|
*** Flow connections
    #+name: two-branch-completed-connections
    | from    | to      | label | colour | style |
    |---------+---------+-------+--------+-------|
    | commit2 | commit1 |       |        |       |
    | commit3 | commit2 |       |        |       |
    | commit4 | commit3 |       |        |       |
    | commit5 | commit4 |       |        |       |
    | commit6 | commit3 |       |        |       |
    | commit7 | commit6 |       |        |       |
    | commit8 | commit5 |       |        |       |
    | commit8 | commit7 |       |        |       |
    | master  | commit8 |       |        |       |
    | rel1    | commit5 |       |        |       |
    | rel2    | commit7 |       |        |       |
    |---------+---------+-------+--------+-------|
*** Flow ranks
    #+name: two-branch-completed-ranks
    | anchor  | node   |
    |---------+--------|
    | commit8 | master |
    | commit5 | rel1   |
    | commit7 | rel2   |
    |---------+--------|

** Rebase merge completed state diagram
   #+name: rebase-completed-state-chart
   #+BEGIN_SRC dot :file ./rebase-completed-state.png :var code=rev-control-flow-builder(legend=rebase-completed-legend,nodes=rebase-completed-elements,graph=rebase-completed-connections,ranks=rebase-completed-ranks)
   $code
   #+END_SRC

   #+RESULTS: rebase-completed-state-chart
   [[file:./images/rebase-completed-state.png]]

*** Flow legend
    #+name: rebase-completed-legend
    | *node* | *label* | *colour* |
    |--------+---------+----------|
*** Flow elements
    #+name: rebase-completed-elements
    | *node*  | *label* | *shape*   | *fillcolor* | *style* |
    |---------+---------+-----------+-------------+---------|
    | commit1 | a8ebfae | circle    | green       |         |
    | commit2 | 21ab34c | circle    | green       |         |
    | commit3 | 785cd72 | circle    | green       |         |
    | commit4 | f471562 | circle    | green       |         |
    | commit5 | a642864 | circle    | green       |         |
    | commit6 | 5e8378c | circle    | green       |         |
    | commit7 | 9076677 | circle    | green       |         |
    | master  | master  | rectangle | yellow      |         |
    | rel1    | Rel1    | rectangle | yellow      |         |
    | rel2    | Rel2    | rectangle | yellow      |         |
    |---------+---------+-----------+-------------+---------|
*** Flow connections
    #+name: rebase-completed-connections
    | from    | to      | label | colour | style |
    |---------+---------+-------+--------+-------|
    | commit2 | commit1 |       |        |       |
    | commit3 | commit2 |       |        |       |
    | commit4 | commit3 |       |        |       |
    | commit5 | commit4 |       |        |       |
    | commit6 | commit5 |       |        |       |
    | commit7 | commit6 |       |        |       |
    | master  | commit5 |       |        |       |
    | rel1    | commit5 |       |        |       |
    | rel2    | commit7 |       |        |       |
    |---------+---------+-------+--------+-------|
*** Flow ranks
    #+name: rebase-completed-ranks
    | anchor  | node   |
    |---------+--------|
    | commit5 | master |
    | commit5 | rel1   |
    | commit7 | rel2   |
    |---------+--------|
* Snippets                                                         :noexport:
** Removing file from all branches
   #+BEGIN_SRC shell
     for tag in $(git tag)
     do
       echo "${tag},$(git log --format="%H,\"%cn\",\"%ci\",\"%s\"" ${tag} | head -1)"
     done | tee ../tag_list.csv
     for branch in $(git branch -r | grep -v HEAD | sed 's/\ \ origin\///')
     do
       git checkout ${branch}
     done
     for branch in $(git branch | sed 's/^..//')
     do
       git checkout -q ${branch}
       du -sk . | sed "s/\./${branch}/"
     done | tee ../branch_sizes.out
     for branch in $(git branch | sed 's/^..//')
     do
       git checkout ${branch}
       git filter-branch --tree-filter 'rm -f largeInformation.md' --prune-empty HEAD
       git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
     done | tee ../cleanup.out
     git reflog expire --expire-unreachable=now --all
     git gc --prune=now
     git fsck --unreachable --no-reflogs
     for branch in $(git branch | sed 's/^..//')
     do
       git checkout -q ${branch}
       du -sk . | sed "s/\./${branch}/"
     done | tee ../branch_sizes_post_process.out
   #+END_SRC
