devops/materials/07-git.md
2026-01-01 00:00:00 +00:00

13 KiB
Raw Blame History

id title
mat-07-git Git

Introduction to source control

Why version control

When you work on software, you inevitably create multiple versions of the same artifact (source code, docs, config). Source control (version control) is used to:

  • track changes over time
  • collaborate safely on the same codebase
  • keep a detailed history and understand “who changed what, when, and why”
  • revert to previous versions
  • integrate with development tooling (IDEs, build automation, CI/CD)

Types of version control systems

Version control systems are commonly grouped into:

  • Local: versioning kept locally on one machine.
  • Centralized: a central server stores the history; clients check out working copies.
  • Distributed: every clone contains the full history; collaboration happens by exchanging commits.

Git overview

Git is a distributed version control system (DVCS) used to track changes in source code during software development. It supports collaboration between multiple developers, branching and merging, and reverting to previous versions. Git works like a stream of snapshots, not deltas.

Git data model and states

Snapshots not deltas

Git stores data as a series of snapshots of the project over time. When you commit, Git records a snapshot of what you staged.

Working directory staging area git directory

A Git project can be viewed as three “places”:

  • Working directory: your checked-out files where you edit.
  • Staging area (index): where you build the next commit by selecting specific changes.
  • Git directory (.git): the database where Git stores committed snapshots and metadata.

File states modified staged committed

Git describes file state using three key states:

  • Modified: changed in the working directory but not committed.
  • Staged: marked to go into the next commit snapshot.
  • Committed: safely stored in the Git database.

Integrity and sha1

Everything in Git is checksummed. Git uses a SHA-1 checksum to identify content; if file contents change, the checksum changes. This supports integrity: you cant change content “silently” without changing the identifier.

Getting started

Installing Git and verifying

After installing Git, verify with:

git --version

First time setup with git config

Set your identity (used in commits):

git config --global user.name "Name Surname"
git config --global user.email "user@provider.com"

Inspect settings:

git config --list
git config user.name
git config user.email

Getting help

Use Gits built-in help:

git help <verb>
git <verb> --help

Getting a repository with git init

To start version control in an existing directory:

cd /path/to/project
git init

This creates a .git directory (the repository “skeleton”). To begin tracking existing files and make an initial commit:

git add <files...>
git commit -m "Initial project version"

Cloning a repository with git clone

To get a copy of an existing repository:

git clone <url>

Unlike a “checkout” in some other systems, cloning pulls down a full copy of nearly all data, including project history.

Recording changes

Tracked and untracked files

Files are either:

  • Untracked: not yet in Gits database.
  • Tracked: known to Git (from the last snapshot and any staged files). Tracked files can be unmodified, modified, or staged.

Checking status with git status

Use git status to see:

  • what branch youre on
  • which files are staged
  • which files are modified but not staged
  • which files are untracked
git status

Short status format

Use the short format:

git status -s

It uses a two-column code. The left column refers to the staging area; the right column refers to the working directory. Examples:

  • ?? untracked file
  • A added to staging area
  • M modified and staged
  • M modified but not staged
  • AM added to staging area and then modified again

Staging with git add

Stage new files or stage changes of tracked files:

git add <file>
git add .

Staging is how you choose what will go into the next commit snapshot.

Viewing changes with git diff

To see what you changed but have not staged yet:

git diff

To see what you staged that will go into the next commit:

git diff --staged

(--cached is a synonym of --staged.)

Committing with git commit

Create a commit (a snapshot of what you staged):

git commit -m "message"

Skipping the staging area with git commit -a

For tracked files, you can skip explicit staging and commit modifications directly:

git commit -a -m "message"

Removing files with git rm

Remove a file from your working directory and stage its removal:

git rm <file>

To keep the file in your working directory but remove it from Git tracking (stage an “untrack”):

git rm --cached <file>

Moving or renaming files with git mv

Rename/move a file:

git mv oldname newname

Ignoring files with gitignore

To ignore generated files, secrets, build outputs, etc., use a .gitignore file. Pattern rules include:

  • Blank lines are ignored.
  • Lines starting with # are comments.
  • Standard glob patterns work (*, ?, [a-z]).
  • A leading / matches from the repository root.
  • A trailing / matches directories.
  • ! negates a pattern.
  • ** can match nested directories.

A repository can have one .gitignore at the root, and it can also have additional .gitignore files in subdirectories; nested rules apply only under that directory.

Viewing history with git log

View commit history:

git log

A compact visualization is:

git log --oneline --decorate --graph --all

Undoing mistakes

Amending the last commit

To change the last commit (for example, fix the message or add missing staged changes):

git commit --amend

Unstaging files

If you staged a file but want to unstage it:

git reset HEAD <file>

Newer Git also provides git restore:

git restore --staged <file>

Discarding local modifications

To discard modifications in the working directory (dangerous; it overwrites your local changes):

git checkout -- <file>

Or with git restore:

git restore <file>

Restore versus reset and safety

git restore was introduced in Git 2.23.0 as an alternative to using git reset/git checkout for some common “undo” cases. Commands that discard changes are dangerous: once you overwrite local modifications, recovering them can be difficult.

Branching

What a branch is

Branching means you diverge from the main line of development and continue work without “messing” with the main line. Git branching is lightweight and switching branches is fast.

In Git, a branch is a lightweight movable pointer to a commit. The default branch name is often master (and on GitHub the default branch is commonly main).

HEAD pointer and current branch

Git keeps a special pointer called HEAD to know what branch youre currently on. When you commit, the current branch pointer moves forward.

Creating and switching branches

Create a new branch:

git branch testing

Switch to a branch:

git checkout testing

Create and switch in one step:

git checkout -b <newbranchname>

Newer Git provides git switch:

git switch <branchname>
git switch -c <newbranchname>

When you check out another branch, your working directory files change to match the snapshot of that branch.

Branches are cheap

A branch is represented by a small file that contains the 40-character SHA-1 checksum of the commit it points to. Creating and deleting branches is therefore cheap.

Divergent history and viewing the graph

If you make commits on different branches, history diverges. You can visualize with:

git log --oneline --decorate --graph --all

Merging

Fast forward merges

If the branch you merge has not diverged (your current branch is directly behind it), Git can do a fast-forward merge: it just moves the branch pointer forward.

Three way merges

If branches have diverged, Git performs a three-way merge using two branch tips and their common ancestor, creating a new merge commit (with 2+ parents).

Merge example:

git merge <branchname>

Deleting branches after merge

After merging a topic branch, you often delete it:

git branch -d <branchname>

Merge conflicts and resolution

If two branches change the same lines, Git cant merge automatically. You will see conflicts (e.g., in git status), and the conflicted file contains conflict markers like:

<<<<<<< HEAD
... your current branch ...
=======
... the other branch ...
>>>>>>> <branchname>

Resolution workflow:

  1. Open the file and resolve the conflict by editing.
  2. Stage the resolved file (git add <file>).
  3. Finish by committing (often git commit after a merge conflict).

Merge versus rebase

Merging and rebasing are two ways of integrating changes from one branch into another.

  • Merge takes the endpoints of branches and merges them, creating a merge commit (when needed).
  • Rebase replays commits from one branch onto another base, creating a “cleaner” linear history, but changing the history of the rebased commits.

Basic rebasing workflow

A common rebase flow is to move a topic branch onto the updated base branch:

git checkout <topic-branch>
git rebase <base-branch>

After resolving any conflicts during a rebase, you continue with:

git rebase --continue

Remotes

Remote repositories and origin

A remote repository is a Git repository hosted elsewhere (for example on GitHub). When you clone, Git typically adds a remote named origin.

Showing and adding remotes

Show remotes:

git remote
git remote -v

Add a remote:

git remote add <shortname> <url>

Fetching and pulling

Fetch downloads data from a remote without merging it into your current work:

git fetch <remote>

Pull fetches and then merges into your current branch (when your branch is set up to track a remote branch):

git pull

Pushing

Push commits to a remote branch:

git push <remote> <branch>

Tracking branches upstream

To set the upstream (tracking) relationship when pushing:

git push -u origin <branch>

Renaming and removing remotes

Rename a remote:

git remote rename <old> <new>

Remove a remote:

git remote remove <name>

Deleting remote branches

Delete a branch on the remote:

git push origin --delete <branch>

Tagging and releases

Lightweight and annotated tags

Tags are typically used to mark releases.

  • Lightweight tag: just a pointer to a commit.
  • Annotated tag: stored as a full object with metadata and a message.

Create an annotated tag:

git tag -a v1.4 -m "my version 1.4"

Create a lightweight tag:

git tag v1.4-lw

Listing and showing tags

List tags:

git tag
git tag -l "v1.*"

Show information for a tag:

git show v1.4

Checking out tags and detached head

If you check out a tag, Git puts you in a detached HEAD state. You can inspect the code, but commits you make wont belong to a named branch unless you create one.

git checkout v2.0.0

Productivity

Git aliases

You can define aliases to shorten commands:

git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status

Aliases can also wrap longer commands, for example:

git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'

Credential helpers

To avoid typing credentials repeatedly, Git can use credential helpers (depending on your OS) to cache or store credentials for Git operations.

Collaboration on GitHub

Forking and pull requests

A common collaboration pattern on GitHub is:

  1. Fork the project (create your copy on GitHub).
  2. Clone your fork locally.
  3. Add the original repository as an upstream remote.
  4. Create a topic branch, make commits, and push to your fork.
  5. Open a pull request from your fork/topic branch into the upstream repository.
  6. Keep your fork updated by fetching from upstream and integrating changes.

Suggested class assignment and homework workflow

The following sequence matches the lectures suggested lab/homework ideas:

  • Create a new repository on GitHub and connect it to a local project.
  • Make commits, inspect status/diff/log, and push to GitHub.
  • Create a new branch, make changes, and merge back.
  • Create a three-branch workflow (for example develop, test, production) and practice merging changes through the branches.
  • Fork a colleagues repository, make changes in a topic branch, and submit a pull request.