Git basics
Goals of the day
- Understand git terminology, structure
- Be comfortable using basic git commands
- Become autonomous to continue your learning journey on your own
Why do we keep doing this?
- report.odt
- report_final.odt
- report_v2_final.odt
- report_final_fixed.odt
- report_final_20220706.odt
- Fear of losing data
- Need to have a version that’s considered "current"
Git to the rescue
"Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. "
Git to the rescue
Initial report
Add table of contents
Add part about foobar
Fix typos
Each change is recorded, which means you basically have a time machine 🤯
Never* fear losing your work again!
* unless you screw up, which happens
Let’s install it!
Today’s most important concepts
- Repository
- Commit
- Branch
- Working directory
- Staging area
Let’s create a repository
$ mkdir myproject
$ cd myproject
$ git init
$ ls -a
.git/
The git repository
apps/
main.py
README.md
Initial report
Add table of contents
Add part about foobar
Fix typos
.git
myproject
Git stores all its data in the .git directory
The git repository
apps/
main.py
README.md
Initial report
Add table of contents
Add part about foobar
Fix typos
.git
myproject
Git stores all its data in the .git directory
Our first commits!
# Create a file named main.py in the "myproject" directory
def say_hello():
# Typo here is on purpose
print("helo!")
Our first commits!
$ git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what
will be committed)
main.py
nothing added to commit but untracked files present
(use "git add" to track)
git status: check the status of the working directory and the staging area
Our first commits!
$ git add main.py
$ git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: main.py
git add: add files to the staging area
Our first commits!
$ git diff --staged
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..0c9e0e1
--- /dev/null
+++ b/main.py
@@ -0,0 +1,2 @@
+def say_hello():
+ print("helo!")
git diff: check the differences between versions of a file
Our first commits!
$ git commit -m "Hello world :)"
[main (root-commit) 6ba367f] Hello world :)
1 file changed, 2 insertions(+)
create mode 100644 main.py
$ git status
On branch main
nothing to commit, working tree clean
git commit: create a commit with the changes from the staging area
Writing a good commit message
Explain what your commit changes in the code (and why)
Writing a good commit message
- ❌ Fix
- ❌ Try something
- ❌ Fix tests
- ❌ Add some code to improve the layout
- ❌ Added a checkout button on the basket page
- ✅ Add a checkout button on the basket page
- ✅ ✅ mantis612 - add a checkout button on the basket page
It’s sometimes a good idea to provide more information
mantis612 - add a checkout button on the basket page Currently users cannot do a checkout because the fixed position button is not always visible. Adding it on the basket page was discussed and validated by the national committee.
1 line of text (~80 chars max)
1 blank line
Explanation
Recovering files
# Delete the main.py file
$ ls -a
.git/
$ git status
On branch main
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: main.py
$ git restore main.py
$ ls -a
.git/
main.py
git restore: restore files in the working directory or in the staging area
Manipulating the git repository

git add
git commit
git checkout
Use git status to check the status of the working directory & staging area
git restore
git restore --staged
Exercise
Fix the typo in the main.py file and record the change in the git repository
Hint: use the add & commit commands
Exercise
# Fix the typo in the main.py file and then:
$ git add main.py
$ git commit -m "Fix typo"
Inspecting the history
$ git log
commit 087a9263a2ea4fe11c384e0ca1699f7741264a9c (HEAD -> main)
Author: Sylvain Fankhauser <sephi@fhtagn.top>
Date: Tue Jun 7 11:49:27 2022 +0200
Fix typo
commit 6ba367f9dd9e564ab18735a3306eec23b2aaa6d1
Author: Sylvain Fankhauser <sephi@fhtagn.top>
Date: Tue Jun 7 11:34:06 2022 +0200
Initial commit
git log: show the commit history
Hint: use `git log -p` to see the changes!
Hint2: use `git log --graph` to see a nice graph!
What is a commit?
commit 087a9263a2ea4fe11c384e0ca1699f7741264a9c Author: Sylvain Fankhauser <sephi@fhtagn.top> Date: Tue Jun 7 11:49:27 2022 +0200 Fix typo main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
A unique identifier (generated)
An author
A date
A message
A set of changes
+ one or several parents
parent 6ba367f9dd9e564ab18735a3306eec23b2aaa6d1
Viewing a specific commit
$ git show 087a9263a2ea4fe11c384e0ca1699f7741264a9c
commit 087a9263a2ea4fe11c384e0ca1699f7741264a9c (HEAD -> main)
Author: Sylvain Fankhauser <sephi@fhtagn.top>
Date: Tue Jun 7 11:49:27 2022 +0200
Fix typo
diff --git a/main.py b/main.py
index 0c9e0e1..d55f52f 100644
--- a/main.py
+++ b/main.py
@@ -1,2 +1,2 @@
def say_hello():
- print("helo!")
+ print("hello!")
git show: show the details of a given object
Annotate a file with its changes
(aka "finding out who to blame for the bug")
$ git blame main.py
^6ba367f (Sylvain Fankhauser 2022-... 1) def say_hello():
087a9263 (Sylvain Fankhauser 2022-... 2) print("hello!")
git blame: show the commit associated with each line of a file
Reverting a change
$ git log -p
commit a0ac2b55d97ec3ca7e70a58870241a1bf0d1328e
Author: Bernard Pivot <bernardi@pivot.fr>
Date: Tue Jun 7 13:54:30 2022 +0200
FRANCISONS TOUT!
diff --git a/main.py b/main.py
index d55f52f..18bfdaa 100644
--- a/main.py
+++ b/main.py
@@ -1,2 +1,2 @@
-def say_hello():
+def dire_bonjour():
print("hello!")
$ git revert a0ac2b55d97ec3ca7e70a58870241a1bf0d1328e
[main 5f6e6c8] Revert "FRANCISONS TOUT!"
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log -p
commit 5f6e6c89fc0e7db8a2958029c8932a46e00f01c7 (HEAD -> main)
Author: Sylvain Fankhauser <sephi@fhtagn.top>
Revert "FRANCISONS TOUT!"
This reverts commit a0ac2b55d97ec3ca7e70a58870241a1bf0d1328e.
diff --git a/main.py b/main.py
index 18bfdaa..d55f52f 100644
--- a/main.py
+++ b/main.py
@@ -1,2 +1,2 @@
-def say_bonjour():
+def say_hello():
print("hello!")
commit a0ac2b55d97ec3ca7e70a58870241a1bf0d1328e
Author: Bernard Pivot <bernard@pivot.fr>
Date: Tue Jun 7 13:54:30 2022 +0200
FRANCISONS TOUT!
diff --git a/main.py b/main.py
index d55f52f..18bfdaa 100644
--- a/main.py
+++ b/main.py
@@ -1,2 +1,2 @@
-def say_hello():
+def say_bonjour():
print("hello!")
git revert: create a commit that reverts the changes of another commit
Working on multiple features in parallel
mantis769: update changelog
mantis722: fix tab label
mantis769: recreate LDAP users
mantis722: show cancelled tickets
Problem: we can’t easily release only mantis769!
Update changelog for release 2.13
mantis769: update changelog
mantis722: fix tab label
mantis769: recreate LDAP users
mantis722: show cancelled tickets
Solution: work on different branches!
Update changelog for release 2.13
Merge branch mantis769
Working on multiple features in parallel
mantis722
mantis769
main
main
A branch is a pointer to a commit
mantis769: two
mantis722: two
mantis769: one
mantis722: one
Solution: work on different branches!
Update changelog for release 2.13
Working on multiple features in parallel
$ git checkout -b mantis769
$ git commit -m "mantis769: one"
$ git commit -m "mantis769: two"
$ git checkout main
$ git checkout -b mantis722
$ git commit -m "mantis722: one"
$ git commit -m "mantis722: two"
main
mantis769
mantis769
mantis769
mantis722
mantis722
mantis722
git checkout: switch branch
The branch pointer moves automatically when you make a new commit!
A branch is nothing more than a label on a commit, really
$ ls .git/refs/heads
main mantis722 mantis769
$ cat .git/refs/heads/mantis722
5f6e6c89fc0e7db8a2958029c8932a46e00f01c7
$ git show-ref mantis722
5f6e6c89fc0e7db8a2958029c8932a46e00f01c7 refs/heads/mantis722
Tags are also labels on commits, but they don’t move once they’re created
git tag: list tags or create a tag on the current commit
Create a branch named "french" where you’ll add a function "dire_bonjour" and a branch "german" where you’ll add a function "hallo_sagen".
Both branches should be based on the main branch.
Exercise
add dire_bonjour
add hallo_sagen
Fix typo
main
french
german
Sharing your work
Everything we did so far was local, which means only you could see your changes
Sharing your work by e-mail
(you probably won’t use this)
$ git format-patch --stdout HEAD^
From 5f6e6c89fc0e7db8a2958029c8932a46e00f01c7 Mon Sep 17 00:00:00 2001
From: Sylvain Fankhauser <sephi@fhtagn.top>
Date: Tue, 7 Jun 2022 13:54:36 +0200
Subject: [PATCH] Revert "FRENCHIZE ALL THE THINGS!"
This reverts commit a0ac2b55d97ec3ca7e70a58870241a1bf0d1328e.
---
main.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/main.py b/main.py
index 18bfdaa..d55f52f 100644
--- a/main.py
+++ b/main.py
@@ -1,2 +1,2 @@
-def say_bonjour():
+def say_hello():
print("hello!")
--
2.36.0
Sharing your work using a central server
(eg. GitHub, Bitbucket, Gitlab)
Push
Pull
Push
Pull
Central server
Git repository
🧑💻
Matthieu
Git repository
👩💻
Mélanie
Git repository
It’s possible to have several remotes!
Interacting with remotes
- git clone: initialize a local repository from a remote
- git push: push the current branch to a remote
- git pull: fetch objects from a remote and update the current branch
- git fetch: fetch objects from a remote
- git remote: add/remove/edit remotes
Exercising remotes
Clone this repository
git@github.com:sephii/git-crash-course
Fix the typo in the README, commit and push the fix
What happens if you’re not the first pushing the fix?
Git internals
Let’s see what’s in the .git directory!
git show-ref: show the commit pointed by the given reference
git ls-tree: show the trees and blobs of the given reference
git cat-file: show the contents of a blob in the tree
git show: show almost anything
Git pull: case 1, new remote objects
A
B
C
Origin
git clone
D
A
B
C
Local copy
origin/main
origin/main
main
git pull
D
main
This is called a "fast-forward merge"
(no merge commit is created, the branch pointer is just moved to a new commit)
Git pull: case 2, new remote objects
& new local objects
A
B
C
Origin
git clone
D'
D
A
B
C
Local copy
D'
E
origin/main
main
origin/main
main
main
A merge commit is a commit that has more than 1 parent!
git pull: fetch objects from the remote and move the branch to the new tip (merging if necessary)
git pull
Fixing conflicts
D
D'
E
main
If D and D' made changes to the same lines of the same files, we’ll need to fix the conflict manually
A
B
C
Fixing conflicts: exercise
Clone this repository
git@github.com:sephii/git-crash-course
Switch to the `fix-typo` branch
git checkout fix-typo
Try to merge the `politeness` branch in it
git merge politeness
What happens? How do you fix this?
Rewriting the last commit
A
B
C
D
origin/main
git commit --amend: remove last commit
and create a new one
Oops
origin/main
$ git commit -m "D"
$ git commit --amend -m "D2"
D2
DON’T DO THIS IF THE COMMIT
HAS BEEN PUSHED
DON’T DO THIS IF THE COMMIT
HAS BEEN PUSHED
DON’T DO THIS IF THE COMMIT
HAS BEEN PUSHED
D O N ’ T
Rewriting history
DANGER ZONE AHEAD
DANGER ZONE AHEAD
DANGER ZONE AHEAD
DANGER ZONE AHEAD
You have been warned.
Rewriting history
A
B
C
D
git rebase: rewrite history (and potentially
screw up your whole repository)
Oops
origin/main
$ git rebase -i A
pick 3e2a4d2 B
pick cce25f3 C
pick ccf7b1b D
edit 3e2a4d2 B
pick cce25f3 C
pick ccf7b1b D
$ # Make some changes…
$ git commit --amend
$ git rebase --continue
B'
C
D
origin/main
origin/main
origin/main
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
I will not rewrite the history once it’s published.
Low-level history rewriting
git reset: move your branch pointer to a given commit
git cherry-pick: replay a commit
A
B
C
D
origin/main
$ git reset --hard B
$ git cherry-pick D
C
D
origin/main
origin/main
D
origin/main
The part where I wish I had slides
Staging parts of files
git add -p: stage only parts of files
git restore -p: remove parts of files from the staging area
-p stands for "patch"
Stashing your work
git stash: stash the changes in your working directory
git stash list: list the contents of the stash
git stash pop: pop changes from the stash and apply them
(these commands work with "-p")
What to do when pushing fails
Recovering from fuck ups
git reflog: show the log of branch tip switching
Viewing differences
Useful revision patterns
- - : "the previously checked commit"
- @{u}: the commit pointed by the remote branch
- A..B : "commits in B that are not in A"
- A...B: difference between the two sets of commits (ie. "commits in A not in B + commits in B not in A")
If we still have time
- - : "the previously checked commit"
- @{u}: the commit pointed by the remote branch
- A..B : "commits in B that are not in A"
- A...B: difference between the two sets of commits (ie. "commits in A not in B + commits in B not in A")
If again we still have time
- Tracking bugs with git bisect
- Using aliases
- Finding commits with grep
- Multiple worktrees
Going further
`git help`
Thank you!
Git basics
By Sylvain Roflmao
Git basics
- 230