Git Basics

Agenda

  • Git structure
  • Basic commands
  • Detached head and dangling commits
  • Merge and Rebase

Git Structure

Main components

  • HEAD - the pointer to the current commit reference
  • Branch - a named pointer to a commit reference
  • Working directory - consists of files you are currently working on
    • States of Git files:
      • Untracked
      • Staged
      • Committed
      • Modified
  • Staging / Index - area of modified files
  • Local repository - container that tracks the changes to the project
  • Remote repository - repository deployed on a server

States of Git files

Git components

Legend

  • For all diagrams, the following markings will be used

Git tree

  • Git stores commits in a tree-like structure. One commit can have zero, one or more parents.

Basic Commands

Basic Commands

CommandScopeDescription
git initRepoCreates an empty Git repository
git cloneRepoClones a repository into a new directory
git branchRepoCreates, lists, renames or deletes branches
git logRepoDisplays a record of commits
git addFile-levelAdds a change in the working directory to the index
git commitCommit-levelCreates a unique snapshot of the staging area
git pushCommit-levelUploads data to a remote repository
git fetchCommit-levelSynchronizes with a remote repository
git pullCommit-levelUpdates the HEAD with the latest changes
git checkoutCommit-levelSwitches between branches or inspects other commits
git checkoutFile-levelDiscards changes or replaces files with versions from other commits
git resetCommit-levelDiscards commits or throws away uncommited changes
git resetFile-levelUnstages a file
git restoreFile-levelDiscards changes in the working directory
git revertCommit-levelUndoes commits

Git commit

  • Creates a unique snapshot of the staging area

Git commit --amend

  • Appends staging area to the previous commit
When you update a commit, its hash will change!

Git push

  • Uploads data to a remote repository

Git fetch

  • Synchronizes with a remote repository
Git fetch DOES NOT affect your working directory or HEAD!

Git pull

  • Updates the HEAD with the latest changes

Git reset and git restore (file-level)

  • git reset discards the staging area (index), git restore discards the working directory
And what should I do when I discard my changes by mistake?

Git reset (commit-level)

Git checkout (commit-level)

  • Inspects other commits/branches

Git checkout - relative

  • HEAD~ - points to the first parent
  • HEAD^2 - points to the second parent
  • HEAD@{N} - points to a loose commit

Detached HEAD and dangling commits

Detached HEAD

  • Occurs when there is no branch pointer for the HEAD
So how do I re-attach a detached HEAD?

Dangling commits

  • git checkout moves the HEAD, git reset also moves the branch pointer
  • Dangling commits are orphans that have no connection to the main tree

Dangling commits and reflog

  • git reflog displays history of all operations
  • Can be used for any kind of undo
  • Example: reflog for the following tree
    1 1b83d80 (HEAD -> master) HEAD@{0}: commit: C
    2 10732cb HEAD@{1}: checkout: moving from feature to master
    3 ece569e (feature) HEAD@{2}: commit: BA
    4 10732cb HEAD@{3}: checkout: moving from master to feature
    5 10732cb HEAD@{4}: commit: B
    6 d2851af HEAD@{5}: commit (initial): A

Merge and Rebase

Clean merge

  • Merges one branch into another. Occurs when there are no parallel commits.

Messy merge

  • Occurs mostly in public branches
Keen knows that this is an ugly approach!
Keen prefers git
rebase instead!
Keen is smart!
Be like Keen!

Git rebase

  • Helps integrate branches so that one smoothly extends another without conflicts
  • May create new commits or discard old ones

Git rebase - example

Git rebase usually creates NEW commits and modifies the worktree!

Git merge vs Git rebase

Git merge vs Git rebase

Pros

  • git merge is a non-destructive operation
  • git rebase gets much cleaner and linear history

Cons

  • If the public branch is very active, git merge can pollute the history
  • git rebase loses the context provided by a merge commit
If you use git merge in a team project too often, your worktree will turn into Guitar Hero

Interactive rebase

  • git rebase -i
  • You can alter commits as they are moved to the new branch
  • Can be used to clean up messy history before performing a clean merge
  • Example:
    1 pick a8f0e62 Implement new selectbox
    2 squash 42ec648 Update docs
    3 fixup 5ebfbb8 Fix a few issues
    4 fixup 41508f6 Fix a few other issues
  • p (pick) - use commit
  • r (reword) - use commit and edit the message
  • e (edit) - use commit and merge with previous commit
  • s (squash) - squash the commit, keep the log message
  • f (fixup) - squash + discard log message
  • x (exec) - run a command using shell

The Golden Rule of rebasing

  • Never rebase on public branches. You would need to use force-push and others will struggle.
  • Here: someone force-pushed commits D and E on remote and others try to pull the changes.

Summary

  • A commit hash can't be changed. When you "update" a commit, git will create a new one
  • git fetch downloads latest changes, git pull also moves the HEAD
  • Detached head occurs when there is no branch pointer for the HEAD
  • git checkout moves the HEAD, git reset also moves the branch pointer
  • If you lose your commits, you can find them via git reflog
  • git rebase creates new commits and modifies the worktree
  • git merge is a non-destructive operation, git rebase loses the context provided by a merge commit
  • Never rebase on public branches
  • Commands we learned: init, clone, status, branch, log, add, commit, switch, whatchanged, push, fetch, pull, checkout, reset, restore, revert, merge, rebase, reflog, diff, remote
  • You can find the complete cheatsheet here