Introduction to Git

by Doug Bell
(he, him, his)
@preaction
preaction
preaction.me/git
CC-BY-SA 4.0

For navigation help, press ?
For speaker view and notes, press S
For full-screen, press F

Version Control

Source Control

Repository

Historical Record

Captain's Log

Developers' Log

Present

Past

Future

❤️Heart❤️

❤️Collaboration❤️

❤️Build / Test❤️

Git

Distributed

Version Control

Fast

Distributed

Simple-Implementation

Simple

Easy-to-Use

IDE

Command-line

Jargon

(#sorry)

Please Ask

Initial Setup

$ git config --global user.name  "Doug Bell"
$ git config --global user.email "doug@preaction.me"

Author of Commits

Start a project

$ git init decktric
Initialized empty Git repository in /Users/doug/decktric/.git/
Work Tree

Files to edit

$ git init decktric
Initialized empty Git repository in /Users/doug/decktric/.git/
$ cd decktric/
$ mojo generate lite_app
  [write] myapp.pl
  [chmod] myapp.pl 744 
$ git status
On branch master

No commits yet

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

    myapp.pl

nothing added to commit but untracked files present (use "git add" to track)
$ git add myapp.pl 
Work Tree
➡️
add
Staging

Preparing to Commit

$ git status
On branch master

No commits yet

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

    new file:   myapp.pl
$ git commit
Terminal showing vim editor to edit git commit message
Terminal showing vim editor with a commit message written
$ git commit
[master (root-commit) a5366cd] initial application skeleton
 1 file changed, 22 insertions(+)
 create mode 100755 myapp.pl 
Work Tree
➡️
add
Staging
➡️
commit
Commit

Committed

$ git status
On branch master
nothing to commit, working tree clean

Commit

Save Point

$ vim myapp.pl
$ mkdir templates
$ vim templates/index.html.ep
$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   myapp.pl

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

    templates/

no changes added to commit (use "git add" and/or "git commit -a")
$ git diff
diff --git a/myapp.pl b/myapp.pl
index 4a11067..e2c1246 100755
--- a/myapp.pl
+++ b/myapp.pl
@@ -9,11 +9,6 @@ get '/' => sub {
 app->start;
 __DATA__

-@@ index.html.ep
-% layout 'default';
-% title 'Welcome';
-<h1>Welcome to the Mojolicious real-time web framework!</h1>
-
 @@ layouts/default.html.ep
 <!DOCTYPE html>
 <html>

Diff

Patch

+ Added

- Deleted

  Unchanged

$ git diff
diff --git a/myapp.pl b/myapp.pl
index 4a11067..e2c1246 100755
--- a/myapp.pl
+++ b/myapp.pl
@@ -9,11 +9,6 @@ get '/' => sub {
 app->start;
 __DATA__

-@@ index.html.ep
-% layout 'default';
-% title 'Welcome';
-<h1>Welcome to the Mojolicious real-time web framework!</h1>
-
 @@ layouts/default.html.ep
 <!DOCTYPE html>
 <html>
diff
Work Tree
➡️
add
Staging
➡️
commit
Commit
$ git commit -a
Commit message editor showing git
status output
Work Tree
➡️
add
Staging
➡️
commit
Commit
templates/
myapp.pl
Commit message editor showing git status output
$ git commit -a
Aborting commit due to empty commit message.
$ git add templates
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   templates/index.html.ep

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

    modified:   myapp.pl
Work Tree
➡️
add
Staging
➡️
commit
Commit

templates/
myapp.pl
templates/
$ git commit -a
$ git commit -a
[master 83557a5] move index template into file
 2 files changed, 3 insertions(+), 5 deletions(-)
 create mode 100644 templates/index.html.ep
$ git log
commit 83557a50e31f510efd67056e2dcd02c95d2d8ed0 (HEAD -> master)
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:28:56 2019 -0500

    move index template into file

commit e7af51a911ea98efd60b833a67fd4555f9c47a38
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:19:00 2019 -0500

    initial application skeleton
diff
log
Work Tree
➡️
add
Staging
➡️
commit
Commit
diff
log
Work Tree
➡️
add
Staging
➡️
commit
Commit

The Basics

Branching

Merging

Branching

New features

Bug fixes

Temporary Storage

Branching

Merging

$ git branch
* master
$ git branch bootstrap
$ git branch
  bootstrap
* master
$ git checkout bootstrap
Switched to branch 'bootstrap'
diff
log
Work Tree
➡️
add
Staging
➡️
commit
Commit
checkout
$ git checkout bootstrap
Switched to branch 'bootstrap'
$ mkdir templates/layouts
$ vim templates/layouts/default.html.ep
$ git add .
$ git status
On branch bootstrap
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   templates/layouts/default.html.ep

$ git commit
[bootstrap 44bb9ea] add bootstrap to default layout
 1 file changed, 10 insertions(+)
 create mode 100644 templates/layouts/default.html.ep
$ git log
commit 44bb9ea3ac98765b5a702346e1ca6167ec2140fd (HEAD -> bootstrap)
Author: Doug Bell <doug@preaction.me>
Date:   Sun Aug 4 14:14:05 2019 -0500

    add bootstrap to default layout

commit 83557a50e31f510efd67056e2dcd02c95d2d8ed0 (master)
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:28:56 2019 -0500

    move index template into file

commit e7af51a911ea98efd60b833a67fd4555f9c47a38
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:19:00 2019 -0500

    initial application skeleton

$ git checkout master
Switched to branch 'master'
$ git log
commit 83557a50e31f510efd67056e2dcd02c95d2d8ed0 (HEAD -> master)
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:28:56 2019 -0500

    move index template into file

commit e7af51a911ea98efd60b833a67fd4555f9c47a38
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:19:00 2019 -0500

    initial application skeleton

$ git log master..bootstrap
commit 44bb9ea3ac98765b5a702346e1ca6167ec2140fd (bootstrap)
Author: Doug Bell <doug@preaction.me>
Date:   Sun Aug 4 14:14:05 2019 -0500

    add bootstrap to default layout

$ git diff master..bootstrap
diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep
new file mode 100644
index 0000000..c56dee9
--- /dev/null
+++ b/templates/layouts/default.html.ep
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<link rel="stylesheet"
+    href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
+<script
+    src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js">
+</script>
+<title><%= title %></title>
+<body>
+%= content
+</body>

Merge

$ git checkout master
Already on 'master'
$ git merge bootstrap
Updating 83557a5..44bb9ea
Fast-forward
 templates/layouts/default.html.ep | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 templates/layouts/default.html.ep
$ git log
commit 44bb9ea3ac98765b5a702346e1ca6167ec2140fd (HEAD -> master, bootstrap)
Author: Doug Bell <doug@preaction.me>
Date:   Sun Aug 4 14:14:05 2019 -0500

    add bootstrap to default layout

commit 83557a50e31f510efd67056e2dcd02c95d2d8ed0
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:28:56 2019 -0500

    move index template into file

commit e7af51a911ea98efd60b833a67fd4555f9c47a38
Author: Doug Bell <doug@preaction.me>
Date:   Sat Jul 27 10:19:00 2019 -0500

    initial application skeleton

$ git log --oneline --graph
* 44bb9ea (HEAD -> master, bootstrap) add bootstrap to default layout
* 83557a5 move index template into file
* e7af51a initial application skeleton

Merge Conflicts

$ git checkout -b api
Switched to a new branch 'api'
$ vim myapp.pl
$ git commit -a
[api d165051] add api url to index template
 1 file changed, 4 insertions(+), 1 deletion(-)
$ git checkout master
Switched to branch 'master'
$ vim myapp.pl
$ git mv templates/index.html.ep templates/home.html.ep
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    templates/index.html.ep -> templates/home.html.ep

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:   myapp.pl

$ git commit -a
[master ddb0b18] rename index to home
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename templates/{index.html.ep => home.html.ep} (100%)
$ git diff ..api
diff --git a/myapp.pl b/myapp.pl
index 547b39b..2481f3f 100755
--- a/myapp.pl
+++ b/myapp.pl
@@ -3,7 +3,10 @@ use Mojolicious::Lite;

 get '/' => sub {
   my $c = shift;
-  $c->render(template => 'home');
+  $c->render(
+    template => 'index',
+    api_url  => 'http://api.example.com/v1',
+  );
 };

 app->start;
diff --git a/templates/home.html.ep b/templates/index.html.ep
similarity index 100%
rename from templates/home.html.ep
rename to templates/index.html.ep
$ git merge api
Auto-merging myapp.pl
CONFLICT (content): Merge conflict in myapp.pl
Automatic merge failed; fix conflicts and then commit the result.

DON'T PANIC

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both modified:   myapp.pl

no changes added to commit (use "git add" and/or "git commit -a")
$ vim myapp.pl
use Mojolicious::Lite;

get '/' => sub {
  my $c = shift;
<<<<<<<< HEAD
  $c->render(template => 'home');
========
  $c->render(
    template => 'index',
    api_url  => 'http://api.example.com/v1',
  );
>>>>>>> d1650513e8e5a5d9a148d68d865348a113f96908
};

app->start;
use Mojolicious::Lite;

get '/' => sub {
  my $c = shift;
<<<<<<<< HEAD
  $c->render(template => 'home');
========
  $c->render(
    template => 'index',
    api_url  => 'http://api.example.com/v1',
  );
>>>>>>> d1650513e8e5a5d9a148d68d865348a113f96908
};

app->start;
use Mojolicious::Lite;

get '/' => sub {
  my $c = shift;
<<<<<<<< HEAD
  $c->render(template => 'home');
========
  $c->render(
    template => 'home',
    api_url  => 'http://api.example.com/v1',
  );
>>>>>>> d1650513e8e5a5d9a148d68d865348a113f96908
};

app->start;
use Mojolicious::Lite;

get '/' => sub {
  my $c = shift;



  $c->render(
    template => 'home',
    api_url  => 'http://api.example.com/v1',
  );

};

app->start;
$ git add myapp.pl
$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   myapp.pl

$ git commit
[master 4e2bcc1] Merge branch 'api'
$ git log
commit 4e2bcc1f89940fceaf98af20c97894d90fae81b5 (HEAD -> master)
Merge: ddb0b18 d165051
Author: Doug Bell <doug@preaction.me>
Date:   Sun Aug 4 14:30:47 2019 -0500

    Merge branch 'api'

commit ddb0b18145e861d5f9701343743b03350d03a03c
Author: Doug Bell <doug@preaction.me>
Date:   Sun Aug 4 14:27:11 2019 -0500

    rename index to home

commit d1650513e8e5a5d9a148d68d865348a113f96908 (api)
Author: Doug Bell <doug@preaction.me>
Date:   Sun Aug 4 14:23:20 2019 -0500

    add api url to index template

    We're going to need this URL later to add a link to the API documentation.

$ git log --oneline --graph
*   4e2bcc1 (HEAD -> master) Merge branch 'api'
|\
| * d165051 (api) add api url to index template
* | ddb0b18 rename index to home
|/
* 44bb9ea add bootstrap to default layout
* 83557a5 move index template into file
* e7af51a initial application skeleton

Backup / Recovery

Worried?

Destructive?

TAR

TApe ARchive

$ cd ..
$ ls
decktric
$ tar --create --gzip --file backup.tar.gz decktric
# tar czf backup.tar.gz decktric
$ ls
backup.tar.gz decktric
$ rm -rf decktric
$ ls
backup.tar.gz
$ tar --extract --gzip --file backup.tar.gz
# tar xzf backup.tar.gz
$ ls
backup.tar.gz decktric
$ cd decktric
$ git status
On branch master
nothing to commit, working tree clean 
$ tar --create  --gzip --file backup.tar.gz decktric
$ tar --extract --gzip --file backup.tar.gz
$ tar czf backup.tar.gz decktric
$ tar xzf backup.tar.gz

Remotes

$ git clone https://github.com/preaction/decktric.git
Cloning into 'decktric'...
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 23 (delta 5), reused 23 (delta 5), pack-reused 0
Receiving objects: 100% (23/23), done.
Resolving deltas: 100% (5/5), done.
$ 
origin
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
$ vim myapp.pl
$ git commit -a -m'add github url'
[master 0ddfead] add github url
 1 file changed, 1 insertion(+)
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean 
$ git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 353 bytes | 353.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To ssh://github.com/preaction/decktric.git
   4e2bcc1..0ddfead  master -> master
$ git push
Everything up-to-date

Pull Changes

$ git push
To ssh://github.com/preaction/decktric.git
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'ssh://git@github.com/preaction/decktric.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details. 
$ git pull origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From ssh://github.com/preaction/decktric
   0ddfead..f7cfaed  master     -> origin/master
Auto-merging myapp.pl
Merge made by the 'recursive' strategy.
 myapp.pl | 1 +
 1 file changed, 1 insertion(+)
$ git pull
Already up to date.
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean
$ git push
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 4 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 669 bytes | 669.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To ssh://github.com/preaction/decktric.git
   713bf1c..ea86ce6  master -> master 

More Merge Conflicts

$ git push
To ssh://github.com/preaction/decktric.git
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'ssh://git@github.com/preaction/decktric.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From ssh://github.com/preaction/decktric
   0ddfead..f7cfaed  master     -> origin/master
Auto-merging myapp.pl
CONFLICT (content): Merge conflict in myapp.pl
Automatic merge failed; fix conflicts and then commit the result. 
$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 1 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

    both modified:   myapp.pl

no changes added to commit (use "git add" and/or "git commit -a")
$ vim myapp.pl
$ git commit -a
$ git commit -a
[master 1be67ae] Merge branch 'master' of ssh://github.com/preaction/decktric
$ git push
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 4 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 647 bytes | 647.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To ssh://github.com/preaction/decktric.git
   f7cfaed..1be67ae  master -> master

That’s all, folks!

Don't Panic

Read the error message

Use git status

Next steps

git help

git help log

Search commit messages

(ticket numbers)

Search changed lines of code

Show the patch in the log

git stash

Put current changes aside

Retrieve them later

git blame

Unfortunate name, useful feature

What commit touched which line

git show <commit>

git hooks

React to events

Run tests on `commit`

Enforce coding standards

Automate ancillary tasks

Wrap Up

Questions?