Back to index

Infrastructure as code

Git

Intro

What you guys think of it

What I think of it

What is Git?

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.
  • Version control system
    • Tell it to keep track of certain files
    • Save the state of files in a historical timeline (repository)
  • Distributed
    • Works offline
    • Several users have their own separate file history
      • These can later on be merged

Installation & Basic Configuration

  • Download the Git binary from git-scm.com
    • On Windows, choose “Run Git and included Linux tools from the Windows Command Prompt” during installation
  • Once installed, tell Git who you are
    
    $ git config --global user.name "Lorem Ipsum"
    $ git config --global user.email lorem@ips.um
  • Let's also ask for colors while we're at it
    $ git config --global color.ui true

Git GUIs

  • Git is shipped with some (very) basic GUI tools
    • gitk, git-gui
  • Other Git GUIs also exist
    Whilst these GUIs are a nice addition, we'll focus on the command line

Getting started

Thank you, thank you. Let's get started. Max, play me over.
(gasps) Looks like someone forgot to feed Max!

Creating a repository

  • Start tracking files in a directory with git init
    
    ~/ikdoeict/git-demo
    $ git init
    Initialized empty Git repository in /Users/roelvs/git-demo/.git/
    
    ~/ikdoeict/git-demo
    $ 
    • Git automatically creates a (hidden) .git folder containing
      • Meta information
      • The entire history

Checking the status of a repository

  • Git knows whenever a file has changed in the repository
  • Use git status to check
    
    ~/ikdoeict/git-demo
    $ touch test.txt
    
    $ ~/ikdoeict/git-demo
    $ git status
    # …
    #
    # Untracked files:
    # …
    #	test.txt
    #
    
  • Git compares the current state of the working directory to the last state stored in the history

Staging & committing

  • To save the changes into the history timeline
    1. Select which files you want to save using git addstaging
    2. Actually save them using git commitcommitting
    
    ~/ikdoeict/git-demo
    $ git add test.txt
    
    ~/ikdoeict/git-demo
    $ git commit -m 'Start tracking test.txt'
    [main (root-commit) 9c43f96] Start tracking test.txt
     0 files changed
     create mode 100644 test.txt
    
  • The current state (actually: a delta) of test.txt is stored in the repository
    • The commit is identified as 9c43f96

Flow visualization

Visual representation of staging and committing in Git

Committing (1)

  • Only staged files are committed

~/ikdoeict/git-demo on main
$ touch test2.txt

~/ikdoeict/git-demo on main
$ echo 'hello' >> test.txt

~/ikdoeict/git-demo on main*
$ git status
# On branch main
# Changes not staged for commit:
# …
#	modified:   test.txt
#
# Untracked files:
# …
#	test2.txt
#

~/ikdoeict/git-demo on main*
$ git add test2.txt

~/ikdoeict/git-demo on main*
$ git status
# On branch main
# Changes to be committed:
# …
#	new file:   test2.txt
#
# Changes not staged for commit:
# …
#	modified:   test.txt
#

~/ikdoeict/git-demo on main*
$ git commit -m 'Start tracking test2'
[main f1c6883] Start tracking test2
 0 files changed
 create mode 100644 test2.txt

~/ikdoeict/git-demo on main*
$ git status
# On branch main
# Changes not staged for commit:
# …
#	modified:   test.txt
#

Committing (2)

  • Stage all files + commit them in one command
    $ git commit -am 'commitmessage'
  • Don't create an extra commit when something was forgotten but amend it
    $ git commit --amend -m 'commitmessage'
  • Write good commit messages
    • English
    • Present tense
  • One commit = one set of changes
    • Don't commit 2 features/bugfixes/etc at once

Staging & Unstaging (1)

  • Stage all files
    $ git add .
  • Stage all .txt files
    $ git add *.txt
  • Stage an entire subfolder
    $ git add subfolder/
  • Unstage files
    $ git reset filename

Visualization

Visual representation of staging, unstaging and committing in Git

Staging & Unstaging (2)

  • Deletions are not staged by default

~/ikdoeict/git-demo on main
$ rm test2.txt

~/ikdoeict/git-demo on main
$ git status
# On branch main
# Changes not staged for commit:
#
#	modified:   test.txt
#	deleted:    test2.txt
#

~/ikdoeict/git-demo on main*
$ git add .

~/ikdoeict/git-demo on main*
$ git status
# On branch main
# Changes to be committed:
# …
#	modified:   test.txt
#
# Changes not staged for commit:
# …
#	deleted:    test2.txt
#

~/ikdoeict/git-demo on main*
$ git add -u .

~/ikdoeict/git-demo on main*
$ git status
# On branch main
# Changes to be committed:
# …
#	modified:   test.txt
#	deleted:    test2.txt
#
#

~/ikdoeict/git-demo on main*
$ git reset test.txt
Unstaged changes after reset:
M	test.txt

~/ikdoeict/git-demo on main*
$ git commit -m 'Deleted test2.txt'
[main 1d7a184] Deleted test2.txt
 0 files changed
 delete mode 100644 test2.txt

~/ikdoeict/git-demo on main*
$ git status
# On branch main
# Changes not staged for commit:
# …
#	modified:   test.txt
#
#

~/ikdoeict/git-demo on main*
$ ls
drwxr-xr-x   4 roelvs  staff  136 Mar 19 21:18 .
drwxr-xr-x  10 roelvs  staff  340 Mar 19 15:49 ..
drwxr-xr-x  13 roelvs  staff  442 Mar 19 21:24 .git
-rw-r--r--   1 roelvs  staff    6 Mar 19 20:44 test.txt

~/ikdoeict/git-demo on main*
$ git commit -am 'Hello'
[main c53f9b6] Hello
 1 file changed, 1 insertion(+)

~/ikdoeict/git-demo on main
$ 
  • Solution: use git add -u
  • Git provides a shorthand git rm file

Checking changes (1)

  • Use git diff file to compare the current state with the previously committed state
    
    ~/ikdoeict/git-demo on main
    $ echo 'more hello' >> test.txt
    
    ~/ikdoeict/git-demo on main*
    $ git diff test.txt
    diff --git a/test.txt b/test.txt
    index ce01362..3477282 100644
    --- a/test.txt
    +++ b/test.txt
    @@ -1 +1,2 @@
    hello
    +more hello
    

Checking the history (1)

  • Use git log to see the commit log
    
    ~/ikdoeict/git-demo
    $ git log
    commit c53f9b6bd0e7271af7c5d856f84f51d9b749d77f
    Author: roelvs <roelvs@bram.us>
    Date:   Tue Mar 19 22:09:32 2013 +0100
    
        Hello
    
    commit 1d7a18481b5f6664d2cf30b1455c6ad1c041caa2
    Author: roelvs <roelvs@bram.us>
    Date:   Tue Mar 19 21:24:13 2013 +0100
    
        Deleted test2.txt
    
    commit f1c68836b8c1f91c16d4f4c0540fca0f251ff946
    Author: roelvs <roelvs@bram.us>
    Date:   Tue Mar 19 20:44:31 2013 +0100
    
        Start tracking test2
    
    commit 9c43f961b1defcc2f4f14526a2b20c4f3c267a62
    Author: roelvs <roelvs@bram.us>
    Date:   Tue Mar 19 16:02:03 2013 +0100
    
        Start tracking test.txt
    
    • Press q to exit the commit log

Checking the history (2)

  • Use git log --oneline to get a concise output
    
    ~/ikdoeict/git-demo
    $ git log --oneline
    c53f9b6 Hello
    1d7a184 deleted test2.txt
    f1c6883 Start tracking test2
    9c43f96 Start tracking test.txt
    
    ~/ikdoeict/git-demo
    $ 
    
  • Filter commits by author
    $ git log --author=name
  • Filter commits in time
    $ git log --since="1 week ago"

Checking the history (3)

  • Ultimate git log
    $ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
    
    ~/ikdoeict/git-demo
    $ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
    * c53f9b6 - (HEAD, main) Hello (16 minutes ago) <roelvs>
    * 1d7a184 - Deleted test2.txt (61 minutes ago) <roelvs>
    * f1c6883 - Start tracking test2 (2 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (6 hours ago) <roelvs>
    
    • Pro tip: create an alias git lg for it
      $ git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
      • From now on, use git lg to get the output as shown above

Git basics summary

  • Create repository
    $ git init
  • Stage file
    $ git add file
  • Unstage file
    $ git reset file
  • Commit staged changes
    $ git commit -m 'message'
  • Check differences in a file (compared to repository)
    $ git diff file
  • Check commit log (using our alias)
    $ git lg

Git basics summary

Don't lose your HEAD!

Welcome to the Head Museum. I'm Leonard Nimoy.

Commit history

  • The entire commit history can be visualized as a timeline
  • Such a timeline is called a branch
    • More than one branch can exist (see further)
    • The default branch is called the main

HEAD

  • The HEAD is a pointer pointing towards the currently checked out (= active) revision (= commit)

Moving the HEAD

  • The HEAD can be moved by checking out a revision
    
    ~/ikdoeict/git-demo on main
    $ git lg
    * c53f9b6 - (HEAD, main) Hello (15 hours ago) <roelvs>
    * 1d7a184 - Deleted test2.txt (16 hours ago) <roelvs>
    * f1c6883 - Start tracking test2 (17 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (22 hours ago) <roelvs>
    
    ~/ikdoeict/git-demo on main
    $ git checkout 1d7a184
    Note: checking out '1d7a184'.
    
    You are in 'detached HEAD' state. You can look around, make experimental
    changes and commit them, and you can discard any commits you make in this
    state without impacting any branches by performing another checkout.
    
    HEAD is now at 1d7a184... Deleted test2.txt
    
    ~/ikdoeict/git-demo on (no branch)
    $ git lg
    * 1d7a184 - (HEAD) Deleted test2.txt (16 hours ago) <roelvs>
    * f1c6883 - Start tracking test2 (17 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (22 hours ago) <roelvs>
    
    ~/ikdoeict/git-demo on main
    $ git checkout f1c6883
    Previous HEAD position was 1d7a184... Deleted test2.txt
    HEAD is now at f1c6883... Start tracking test2
    
    ~/ikdoeict/git-demo on (no branch)
    $ git lg
    * f1c6883 - (HEAD) Start tracking test2 (17 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (22 hours ago) <roelvs>
    
    ~/ikdoeict/git-demo on main
    $  git checkout main
    Previous HEAD position was f1c6883... Start tracking test2
    Switched to branch 'main'
    
    ~/ikdoeict/git-demo on main
    $ git lg
    * c53f9b6 - (HEAD, main) Hello (15 hours ago) <roelvs>
    * 1d7a184 - Deleted test2.txt (16 hours ago) <roelvs>
    * f1c6883 - Start tracking test2 (17 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (22 hours ago) <roelvs>
    
    ~/ikdoeict/git-demo on main
    $ 
    • When checking out a revision the files in your working directory change to the state of the selected revision

Visualization



Visual representation of moving the HEAD using git checkout

Unstaging revisited

  • Unstage one file
    $ git reset filename
  • Unstage all files
    $ git reset HEAD

Discarding changes

  • Unstaged changes can be discarded
    $ git checkout -- filename
    • The selected file will go back to the last committed state
  • Unstage all + discard all changes
    $ git reset HEAD --hard
    • The entire working directory will go back to the last committed state
    • Cannot be undone (!!)
  • Unstage all + stash all changes
    $ git stash
    • The entire working directory will go back to the last committed state
    • Can be undone as the state is saved in a stash

Remotes

Well, let's at least throw this TV away,
the batteries in the remote are gettin low.

Remotes

  • A repository can be synched with a server
    • In Git this is called a remote
    • A remote is identified by a name, defaulting to origin, and a URL
    • Keep a local copy in sync with the remote by pushing and pulling
    • Several users can push/pull to/from the same remote
    • Possible to define more than one remote (distributed)
  • Visualization

Visual representation of a Git remote

Setting up shop (1)

  • If a local copy of a repository doesn't exist yet
    • Clone the repository locally using git clone url
    • A local copy of the main + the entire commit history is created
    
    ~/ikdoeict
    $ git clone git@github.com:fabpot/Silex.git
    Cloning into 'Silex'...
    remote: Counting objects: 6612, done.
    remote: Compressing objects: 100% (1908/1908), done.
    remote: Total 6612 (delta 4225), reused 6317 (delta 4008)
    Receiving objects: 100% (6612/6612), 1.28 MiB | 176 KiB/s, done.
    Resolving deltas: 100% (4225/4225), done.
    
    ~/ikdoeict
    $ cd Silex
    
    ~/ikdoeict/Silex on main
    $ git log --oneline
    59e7dbd merged branch davedevelopment/add-doc-info-to-docs (PR #647)
    6a4fffe Added a note about writing documentation
    8e6d30a merged branch davedevelopment/form-extension-points (PR #553)
    7c38c9a Add services allowing for form type extensions and guessers
    fd3ba62 merged branch GromNaN/remember-me (PR #645)
    adc172b Add support for remember-me with RememberMeServiceProvider
    fcd93b3 added a note about all possible options for the session (refs #633)
    a31…
    …
    
    • Clone a repo in the current directory using git clone url .

Setting up shop (2)

  • If a local copy of a repository already exists
    • Tell the repo where to find the remote: git remote add name url
    • If the remote repository is empty, push your main to it
    
    ~/ikdoeict/git-demo on main
    $ git remote add origin git@github.com:roelvs/git-demo.git
    
    ~/ikdoeict/git-demo on main
    $ git push origin main
    Counting objects: 9, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (5/5), done.
    Writing objects: 100% (9/9), 705 bytes, done.
    Total 9 (delta 1), reused 0 (delta 0)
    To git@github.com:roelvs/git-demo.git
     * [new branch]      main -> main
    
    ~/ikdoeict/git-demo on main
    $ 
    • If the remote repository is not empty … (see further)

Push & Pull

  • Publish locally committed changes
    $ git push origin main
    • Use git push and it'll default to origin and main
  • Pull changes from the server
    $ git pull
    • Will fetch the changes of the tracked branch and merge them into the locally active branch
      • In this example: origin/mainmain

Inspecting remotes

  • List all remotes
    ~/ikdoeict/git-demo on main
    $ git remote show
    origin
  • Inspect one remote
    ~/ikdoeict/git-demo on main
    $ git remote show origin
    * remote origin
      Fetch URL: git@github.com:roelvs/git-demo.git
      Push  URL: git@github.com:roelvs/git-demo.git
      HEAD branch: main
      Remote branch:
        main tracked
      Local ref configured for 'git push':
        main pushes to main (up to date)

Branching

Imagine that this line represents time. At some point in the past, the timeline skewed into this tangent creating an alternate 1985.

Branches

  • The default branch is main
  • List all branches
    $ git branch
  • Create other branches to develop experimental features
    $ git branch experimental
    • Branches are created locally
  • Activate (checkout) a branch
    $ git checkout experimental
    • The head will be moved to the new branch

Branching off

  • Creating an experiment branch based on the main
    
    									
    ~/ikdoeict/git-demo on main
    $ git branch
    * main
    
    ~/ikdoeict/git-demo on main
    $ git branch experiment
    
    ~/ikdoeict/git-demo on main
    $ git branch
      experiment
    * main
    
    ~/ikdoeict/git-demo on main
    $ git checkout experiment
    Switched to branch 'experiment'
    
    ~/ikdoeict/git-demo on experiment
    $ git branch
    * experiment
      main
    

Visualization



Visual representation of creating and switching to a branch

Committing changes

  • Changes are committed on the active branch
    
    ~/ikdoeict/git-demo on experiment
    $ touch exp.txt
    
    ~/ikdoeict/git-demo on experiment*
    $ git add .
    
    ~/ikdoeict/git-demo on experiment*
    $ git commit -m 'Start tracking exp.txt'
    [experiment a65b9d7] Start tracking exp.txt
     0 files changed
     create mode 100644 exp.txt
    
    ~/ikdoeict/git-demo on experiment
    $ git lg
    * a65b9d7 - (HEAD, experiment) Start tracking exp.txt (7 seconds ago) <roelvs>
    * c53f9b6 - (origin/main, main) Hello (15 hours ago) <roelvs>
    * 1d7a184 - Deleted test2.txt (16 hours ago) <roelvs>
    * f1c6883 - Start tracking test2 (17 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (22 hours ago) <roelvs>
    
    ~/ikdoeict/git-demo on experiment
    $ git checkout main
    Switched to branch 'main'
    
    ~/ikdoeict/git-demo on main
    $ ls
    drwxr-xr-x   4 roelvs  staff  136 Mar 20 20:19 .
    drwxr-xr-x  11 roelvs  staff  374 Mar 20 15:53 ..
    drwxr-xr-x  14 roelvs  staff  476 Mar 20 20:19 .git
    -rw-r--r--   1 roelvs  staff    6 Mar 20 14:38 test.txt
    
    ~/ikdoeict/git-demo on main
    $ echo 'on the main right now' >> test.txt
    
    ~/ikdoeict/git-demo on main*
    $ git add .
    
    ~/ikdoeict/git-demo on main*
    $ git commit -m 'on the main'
    [main 0ea8dd4] on the main
     1 file changed, 1 insertion(+)
    
    ~/ikdoeict/git-demo on main
    $ git lg
    * 0ea8dd4 - (HEAD, main) on the main (2 seconds ago) <roelvs>
    * c53f9b6 - (origin/main) Hello (15 hours ago) <roelvs>
    * 1d7a184 - Deleted test2.txt (16 hours ago) <roelvs>
    * f1c6883 - Start tracking test2 (17 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (22 hours ago) <roelvs>
    

Visualization



Visual representation of committing on different branches

Merging changes

  • Include changes from an other branch with git merge
    • Changes made otherbranch are merged into the HEAD
      • Three way merge between common ancestor and two last branch snapshots
    • A merge commit is created
    
    ~/ikdoeict/git-demo on main
    $ git merge experiment
    Merge made by the 'recursive' strategy.
     0 files changed
     create mode 100644 exp.txt
    
    ~/ikdoeict/git-demo on main
    $ git lg
    *   965d016 - (HEAD, main) Merge branch 'experiment' (5 seconds ago) <roelvs>
    |\
    | * a65b9d7 - (experiment) Start tracking exp.txt (6 minutes ago) <roelvs>
    * | 0ea8dd4 - on the main (2 minutes ago) <roelvs>
    |/
    * c53f9b6 - (origin/main) Hello (22 hours ago) <roelvs>
    * 1d7a184 - Deleted test2.txt (23 hours ago) <roelvs>
    * f1c6883 - Start tracking test2 (24 hours ago) <roelvs>
    * 9c43f96 - Start tracking test.txt (28 hours ago) <roelvs>
    

Visualization


Visual representation of merging changes

Cleaning up

  • Delete branches you don't need anymore
    $ git branch -d branchname
    • If a branch hasn't been merged yet, Git will warn you
    • Override warning using -D instead of -d
    
    ~/ikdoeict/git-demo on main
    $ git branch -d otherbranch
    error: The branch 'otherbranch' is not fully merged.
    If you are sure you want to delete it, run 'git branch -D otherbranch'.
    
    ~/ikdoeict/git-demo on main
    $ git branch -D otherbranch
    Deleted branch otherbranch (was e079840).
    

Handling Conflicts

Hold tight!

Handling conflicts (1)

  • When merging, things can go wrong
    • e.g. the same line of code has been edited
    • When a merge conflict occurs, the merge will pause
    • Manual intervention (choosing which version to keep) is needed
    
    ~/ikdoeict/git-demo on main
    $ echo 'something for exp' >> exp.txt
    
    ~/ikdoeict/git-demo on main*
    $ git add .
    
    ~/ikdoeict/git-demo on main*
    $ git commit -m 'change exp.txt'
    [main babbcd3] change exp.txt
     1 file changed, 1 insertion(+)
    
    ~/ikdoeict/git-demo on main
    $ git checkout experiment 
    Switched to branch 'experiment'
    
    ~/ikdoeict/git-demo on experiment
    $ echo 'a different line for exp.txt' >> exp.txt
    
    ~/ikdoeict/git-demo on experiment*
    $ git add .
    
    ~/ikdoeict/git-demo on experiment*
    $ git commit -m 'change exp.txt (from experiment)'
    [experiment 2925064] change exp.txt (from experiment)
     1 file changed, 1 insertion(+)
    
    ~/ikdoeict/git-demo on experiment
    $ git checkout main
    Switched to branch 'main'
    
    ~/ikdoeict/git-demo on main
    $ git merge experiment
    Auto-merging exp.txt
    CONFLICT (content): Merge conflict in exp.txt
    Automatic merge failed; fix conflicts and then commit the result.
    
    ~/ikdoeict/git-demo on main*
    $ git status
    # On branch main
    # Unmerged paths:
    #   (use "git add/rm <file>..." as appropriate to mark resolution)
    #
    #	both modified:      exp.txt
    #
    
    ~/ikdoeict/git-demo on main*
    $ cat exp.txt 
    <<<<<<< HEAD
    something for exp
    =======
    a different line for exp.txt
    >>>>>>> experiment
    
    ~/ikdoeict/git-demo on main*
    $ subl exp.txt
    
    ~/ikdoeict/git-demo on main*
    $ git add exp.txt
    
    ~/ikdoeict/git-demo on main*
    $ git commit
    [main 80de07c] Merge branch 'experiment'
    
    ~/ikdoeict/git-demo on main
    $ 
    • → Fix the conflict, stage the file and commit

Handling conflicts (2)

  • Conflicted file contents
    
    <<<<<<< HEAD
    something for exp
    =======
    a different line for exp.txt
    >>>>>>> experiment
    • Resolve manually in a text editor
    • Choose version from HEAD
      $ git checkout --ours conflictedfile
    • Choose version from otherbranch
      $ git checkout --theirs conflictedfile

Rebasing (1)

  • Next to merging one can also rebase
  • No three way merge but
    1. Rewinds to the common ancestor
    2. Forwards to the last commit of the branch
    3. Applies the commits of the current branch on top of that state
    4. That final state is saved as the original branch
  • Roughly translated: inject the changes made on another branch into your branch to stay up-to-date.

Rebasing (3)

  • Rule #1 of rebasing
    • Don't rebase onto a branch that is shared with others
    • Put differently: only rebase on local featurebranches
    • Put differently, again: don't ever rebase onto your main
  • Rebase often to prevent potential merge conflicts
  • If the featurebranch is completed, merge it into the main

Rebasing Example


~/ikdoeict/git-demo on main
$ git lg
* 1e7f02e - (HEAD, main) A change comtd on main (12 seconds ago) <roelvs>
* 80de07c - First commit! (2 minutes ago) <roelvs>

~/ikdoeict/git-demo on main
$ git checkout experiment
Switched to branch 'experiment'

~/ikdoeict/git-demo on experiment
$ git lg
* 669ae62 - (HEAD, experiment) A 2nd change comtd on experiment (34 seconds ago) <roelvs>* a9bdacb - A change comtd on experiment(69 seconds ago) <roelvs>
* 80de07c - First commit! (2 minutes ago) <roelvs>

~/ikdoeict/git-demo on experiment
$ git rebase main
First, rewinding head to replay your work on top of it...
Applying: A change comtd on experiment
Applying: A 2nd change comtd on experiment

~/ikdoeict/git-demo on experiment
$ git lg
* dba0673 - (HEAD, experiment) A 2nd change comtd on experiment (2 seconds ago) <roelvs>* 84484e4 - A change comtd on experiment(2 seconds ago) <roelvs>
* 1e7f02e - (main) A change comtd on main (54 seconds ago) <roelvs>
* 80de07c - First commit! (3 minutes ago) <roelvs>

Note: New commit hashes are generated as the patches are applied on top of the rewind/ffwd!

Visualization


Visual representation of git rebase

Visualization bis

Alternate visual representation of git rebase

Rebase conflicts

  • About the same scenario as when a merge conflict happens
    • Fix the conflict manually
    • Add the fixed file
      $ git add conflictedfile
    • Continue the rebase
      $ git rebase --continue
      • Aborting the rebase is also possible
        $ git rebase --abort

Publishing/Pulling branches

  • Publish a branch
    $ git push origin localbranch:remotebranch
  • Delete a remote branch
    $ git push origin :remotebranch
  • Create local branch based on remote branch
    $ git checkout -b localbranch remote/remotebranch
  • Update remote branch list
    $ git remote update

Collaboration

Yes, we have to work together, and not
have this fight I was definitely winning.

Collaboration

  • Knowing how to branch != knowing how to collaborate
  • When collaborating, maintain this flow
    
    
    # 1. Make sure the main is up-to-date
    $ git checkout main
         $ git pull
    
    # 2. Create a featurebranch based on the main
    $ git checkout -b featurebranch
    
    # 3. Develop, stage, and commit your feature on the featurebranch.
         When finished continue to step 4
    
    # 4. Make sure the main is still up-to-date
    $ git checkout main
         $ git pull
    
    # 5. Rebase the main onto the featurebranch
         (skip this step if main remained unchanged since step 1)
    $ git checkout featurebranch
         $ git rebase main
    
    # 6. Merge the featurebranch onto the main
    $ git checkout main
         $ git merge featurebranch
    
    # 7. Push the main
    $ git push origin main
    
    # 8. Clean up
    $ git branch -d featurebranch
    
    # 9. Rinse. Repeat

Few pointers

  • Don't ever develop on the main, but on featurebranches
    • In case that happens use git pull --rebase to minimize the situation and keep the main clean (#). From then on create a featurebranch and continue
  • The main must at all times contain deployable code
  • Keep your featurebranches local

Undoing commits

  • Undo last commit
    $ git revert HEAD~1
    • Creates a new undo commit → the faulty commit will always be accessible by checking out that commithash!
  • Possible to undo a commit without keeping it in the history only if it hasn't been pushed yet (two methods)
    $ git rebase -i commithash
    $ git rebase -i HEAD~2
    • Alternatively checkout the commithash before the faulty one and branch off

GitHub

Gitlab

GitHub and Gitlab are …

  1. A website to browse Git repos
    • Browse branches
    • Inspect commmits (example)
    • Issues
    • Pull Requests

Github and Gitlab are …

  1. A remote to push your repositories to
    • Public / Private (paid account)
  2. Embraced by the open-source community

PLEASE NOTE: GITHUB/GITLAB IS NOT GIT!

AGAIN: GITHUB/GITLAB IS NOT GIT!

Forking

If you don't like my code, Fork off!
  • Clone a repo from one github account to an other one
  • Create forks to develop your own features/your own version of the project
    • Develop on a local featurebranch
    • Publish featurebranch when ready to your own GitHub remote
    • Do a pull request to see your changes implemented in the original project repo

Forking Flow (GitHub)


# 1. Create a fork on GitHub
e.g. clone fabpot/Silex to roelvs/Silex

# 2. Clone your repo locally
$ git clone git@github.com:roelvs/Silex.git

# 3. Create a featurebranch based on the main
$ git checkout -b featurebranch

# 4. Develop, stage, and commit your feature on the featurebranch.
When finished continue to step 5

# 5. Publish your featurebranch on GitHub
$ git push origin localbranch remotebranch

# 6. Do a pull request via GitHub and await merging

# 7. Rinse. Repeat.
Make sure your main is in sync with the original main one!
     (add the original repo as remote and `git fetch` and `git rebase original/main`)

Or, alternatively, do it via the Github website ;-)

Merging Pull Requests

# 1. Checkout your main branch
$ git checkout main

# 2. Add a new remote named 'otherdude'
$ git remote add otherdude git://github.com/otherdude/Project.git

# 3. Fetch information about all branches on the 'otherdude' remote
$ git fetch otherdude

# 4. Merge 'otherdude/featurebranch' into your main
$ git merge otherdude/featurebranch

# 5. Push your newly-merged branch back to GitHub
$ git push origin main

Or, alternatively, do it via the GitHub website ;-)

A few more things

Let's go. If I say one more thing,
I might say it with my evening boot.

Git Ignore File

  • Git will track all files in the working directory for changes
  • Ignore certain files by placing their name in .gitignore Thumbs.db app.db *.log vendor/* node_modules/* config.php
  • .gitignore must be committed into the repository

Config files

  • Don't commit config files such as config.php
  • Add config.php to .gitignore and provide a config.sample.php instead

Don't believe me? Check Leaked credentials on GitHub.

Partially staging files

  • Commits must contain only one set of changes
  • In case of several changes, choose which changes may be staged in Patch Mode using git add -p file

~/ikdoeict/ikdoeict-website on main*
$ git add -p index.html
diff --git a/index.html b/index.html
index 3fc8413..d7af84e 100644
--- a/index.html
+++ b/index.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <head>
-	<title>Home | Ikdoeict.BE</title>
+	<title>Home | IkdoeICT.BE</title>
 	<meta charset="utf-8" />
 	<link rel="stylesheet" href="css/normalize.css" />
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y

@@ -176,7 +176,7 @@
     </section>
     <footer>
-	<p>Copyright (c) 2021 IkdoeICT.be</p>
+	<p>Copyright (c) 2022 IkdoeICT.be</p>
     </footer>
 </div>
 Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? n

~/ikdoeict/ikdoeict-website on main*
$ git status
# On branch main
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   index.html
#
# 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:   index.html
#

~/ikdoeict/ikdoeict-website on main*
$ git commit -m 'title casing'
[main fc91e11] title casing
 1 file changed, 1 insertion(+), 1 deletion(-)

~/ikdoeict/ikdoeict-website on main*
$ git diff index.html
diff --git a/index.html b/index.html
index 7602651..d7af84e 100644
--- a/index.html
+++ b/index.html
@@ -176,7 +176,7 @@
     </section>
     <footer>
-	<p>Copyright (c) 2021 IkdoeICT.be</p>
+	<p>Copyright (c) 2022 IkdoeICT.be</p>
     </footer>
 </div>

~/ikdoeict/ikdoeict-website on main*
$ git add .

~/ikdoeict/ikdoeict-website on main*
$ git commit -m 'copyright 2022 instead of 2021'
[main c36c7be] copyright 2022 instead of 2021
 1 file changed, 1 insertion(+), 1 deletion(-)

Practice!

  • I learned Git by just going for it. You should too.
  • I stil have much to learn about Git
    • … but I know how to Google when in need
    • … but I know how to read (a free book on Git)

Want more?!

  • Stashing
  • Tagging
  • Cherry Picking
  • Continuous Integration
  • Commit hooks

Questions?

(Press ↓ to see some frequently asked ones)

Why not just use Onedrive?

  • Yes, your files will be synced
  • But …
    • No proper collaboration (changes can be overwritten by others)
    • No all-of-the-time deployable code (mid development you cannot deploy your code)
    • No experimental features (you cannot start an experiment on a separate branch)
    • No author information (who broke what?)
    • No going back in time (limited to a few days in Dropbox)
    • No proper timeline (what, you're gonna zip up your files per feature developed? → That's versioning!)
  • And oh: don't ever share a folder that is a git repo

Do I have to remember all those commands?

  • No, sometimes I have to lookup one too.
    That's perfectly fine.
  • It's allowed to use a GUI but you should have a (vague) idea of what is happening in the background
  • Know the basic concepts (stage, commit, push, pull, merge, rebase)

I'll be fine without Git, right?

  • Alas, no dice. Whether you like it or not you'll have to use Git if you're ever going to do something in software/web
    • Above that it's a requirement for some of our courses
  • We know it's tough, but hang on until you get the gist of it
    • There's memory in repetition. There's memory in repetition
    • Truth be told, it took me over a year to get to know the commands I know right now, but I persevered.

Sources