Beginner

Git Fundamentals

This is an introduction to the foundations of Git, the hugely popular version control system that is used to manage code projects by the largest software companies around the world, all t...

Table of Contents

  1. Course Overview
  2. Thinking in Git
  1. Configure your local environment to start using Git
  1. Work in a local depot
  1. Working with others in a shared repository
  1. Merge conflicts: what are they and how to resolve them?
  1. How to modify and correct your commits
  1. Popular Team Workflows
  1. Summary and next steps

1. Course Overview

Welcome to this Git Fundamentals training presented by Aaron Stewart. This is an introduction to the foundations of Git, the hugely popular version control system that is used to manage code projects by the largest software companies around the world, all the way down to small startups.

This training is primarily aimed at developers, but is also suitable for technical project and program managers, content writers, or anyone who needs to review, contribute, or simply better understand a project maintained and monitored by Git.

What you will learn

  • Thinking in Git: understand its fundamental characteristics and the main steps to manage and track changes within a project.
  • Install and configure Git locally on your own computer on Mac, Windows and Linux, and start using Git to track and manage changes in new and existing projects.
  • Working with Others in a Shared Git Environment: Host your Git project on a network server for others to view and contribute to, and use best practices for working effectively with team members while maintaining different environments.
  • Edit and reset changes, resolve merge conflicts that may arise when working on conflicting changes, and discover common development workflows.

At the end of this training, you will know the fundamentals of Git, which will allow you to better understand and apply your knowledge in your next Git project.


2. Thinking in Git

What is Git?

Git is, by far, the most widely used version control system in the world today. Developers use it, non-developers use it, and pretty much anyone who contributes to, manages, or monitors projects that require versioning is most likely using it.

It is a fundamental tool for any technology company, and these days every company has to be a technology company to innovate or simply stay relevant.

Formal definition of Git

Git is a version control system, also known by the acronym VCS (Version Control System). Version control refers to the process of saving files or versions throughout the life stages of a project, allowing you to retrieve past versions at any time.

The best metaphor for understanding version control is that of a time machine. Git gives you the ability to go back to the past at any point during your development.

What Git is not

The goal of this course is not to be a comprehensive guide to everything Git. There is a lot of information beyond the scope of this course. The goal is to give you a solid understanding of the fundamentals that will provide you with a solid foundation and help you learn more.


The characteristics of Git

Git has a reputation for being confusing or having a steep learning curve, not to mention the fear of running a Git command that one doesn’t fully understand, with unintended consequences.

Understanding the features of Git and how it tracks and manages versions of your project early in your learning helps reduce that steep learning curve.

Git is distributed

Git is a distributed version control system (DVCS — Distributed Version Control System). Unlike centralized version control systems (like SVN or CVS), each developer has a complete copy of the entire project history on their own local machine. This means you don’t need a network connection to perform most Git operations.

Git uses snapshots, not deltas

Git does not track version changes as a simple list of file-based changes between one version and another, representing only changes from a base version of a file. These version differences are commonly called deltas or diffs.

Instead, Git stores each saved version of your project as a complete snapshot of the entire project file system at that precise point in time, not just the changed files and their deltas.

This snapshot captures everything in the project, including its history and all its metadata. You can reference old snapshots at any time, and new snapshots are created when your project changes.

Example:

  • For Git, the version 2 snapshot captures:
  • The modification made to file A
  • A full file reference for file B from a previous snapshot (since file B was not changed in version 2, it still includes a full reference to the entire file and all its contents in the version 2 snapshot)
  • Change to C file

Git is local

Everything in Git happens locally on your machine. Even if you’re working in a network-shared Git repository, all basic operations — viewing history, creating branches, making commits — don’t require a network connection.

Git is explicit

Git doesn’t do anything automatically without you telling it to do so. When you add a new file to an existing Git project, Git will not automatically start tracking that file — you must explicitly tell it to do so. This gives you more control over how and when you make your Git commands.

Git is healthy

Git uses checksums (SHA-1 checksums) for everything it tracks. Each commit, each file, each directory is identified by a unique hash. This ensures that you cannot modify the contents of a file or directory without Git knowing.


The statuses of your files

It is important to understand the different states of your files and the different states those files will move into as you make and save changes.

The two main states of a file

With a Git project, a file can be in one of the following two states:

  1. Tracked: These are files that were in the last Git snapshot of the project. Once you tell Git to track a file, Git will continue to track that file until you tell it to stop. Warning: Telling Git to stop tracking files is a destructive command, as you will lose metadata and Git tracking for that file.

  2. Untracked: These are files that exist in your project, but that you have not yet explicitly told Git to track.

The three statuses of a tracked file

Once a file is tracked, it can reside in one of three different statuses:

  1. Unmodified: You are tracking the file, but there are no unsaved changes since the last time it was saved in this Git snapshot.

  2. Modified: A file will enter this status when you have made changes but have not yet saved them in a Git commit. The modified files reside in the working directory.

  3. Staged: A file will move to this status when you have told Git that you want to include this file in your next commit. Indexed files reside in the staging area.

The typical workflow

[Fichier non suivi]
        |
    git add
        |
        v
[Staged / Indexé] -----> git commit -----> [Unmodified / Non modifié dans l'historique]
        ^                                           |
        |                                     (modification)
    git add                                         |
        |                                           v
[Modified / Modifié dans le working directory] <----

The 3 Git directories

Git uses three directories to store and manage your Git project data. The different statuses mentioned above are stored in one of these three directories.

1. The .git directory (local history)

When you initialize Git for the first time in a project, it creates a hidden directory called .git stored in the root of your project. It is in this .git directory that all Git metadata and tracking is stored for each saved snapshot of your project.

This directory is called the local history, and it is where the unmodified status of your files lives. It’s basically a folder that contains all your saved snapshots of your Git project that you can view at any time.

Important: Never manually modify the contents of the .git directory. This could corrupt your deposit.

2. The Working Directory

As the name suggests, this is the directory where you do work in your project when you make changes to tracked files in your Git project. This is where the modified status of your files lives.

The working directory is one of two directories that will always remain local on your machine. This is considered a work in progress area, and changes that remain in this area will always be considered still work in progress.

3. The staging area (Staging Area / Index / Cache)

This is where files are moved when you want to commit or save your changes to a Git snapshot. This directory is often called the staging area, but it is also often called index or cache. This is where files in staged status live, waiting for you to save them in a commit.

The staging area is also local to your machine, but it serves as a buffer between your current work and your commit history.

Summary of the 3 directories

DirectoryLocationFile Status
.git (local history)Hidden in the project rootUnmodified (committees)
Working DirectoryYour working directoryModified
Staging Area (Index/Cache)Local buffer zoneStaged

Introduction to common Git commands

Git is explicit: we have to tell it what to do before it does it. We use specific commands and sometimes options with those commands to be even more specific about how we want Git to do something.

In all, there are over 150 different Git commands, and most, if not all, can take options that further extend their capabilities. About 20 to 30 of these commands are considered fundamental or common.

From this point on, we’ll call our Git project a repository. This is the term Git uses to describe the project.

Git Command Categories

Basic commands are grouped into the following categories:

Git Basics
OrderDescription
git initInitializes a new Git repository in the current directory
git statusDisplays the current status of the repository (modified, indexed, untracked files)
git addAdds files to the staging area
git commitSave indexed changes to a new commit
git diffShows differences between edited files and their previous versions
git logShow commit history
Git Branches
OrderDescription
git branchList, create or delete branches
git checkoutSwitch between branches or restore files
git mergeMerge a branch into the current branch
Git Repositories
OrderDescription
git cloneClone a repository into a new directory
git remoteManages connections to remote repositories
git pushSend local commits to a remote repository
git fetchGet changes from a remote repository without merging them
git pullRetrieves and merges changes from a remote repository
Undoing Changes
OrderDescription
git amendEdit last commit
git resetResets repository state to a previous commit
git revertCreates a new commit that reverts changes from a previous commit
git reflogShows a log of all HEAD positions
git cherry-pickApply changes from a specific commit to the current branch

Coffee Analogy: Steve and Wired Brain Coffee

To illustrate Git concepts throughout this training, we use a coffee shop analogy to make these concepts more concrete.

Steve’s Story

Steve is the sole owner of a well-known downtown coffee shop called Wired Brain Coffee. Steve manages all operations and even developed most of the cafe’s recipes himself. To maintain the popularity of his coffee, he constantly tries new ideas by modifying existing recipes and changing some techniques and ingredients.

He wants to keep the existing recipes, but also follow all his changes in case he decides to modify the dish of the month.

Steve’s problems without Git

Currently, Steve stores all of these recipe files on his computer, and when he wants to make a change, he edits the actual file and then saves it again with a different recipe name. Its approach to backing up files is common and simple, but as we’ve learned, it’s incredibly error-prone:

  • Steve made several mistakes and even accidentally backed up over files he didn’t intend to change.
  • Steve sometimes works on his home computer as well as other devices. This made it difficult to maintain an up-to-date sync of the changes he made across these multiple devices.
  • Steve also wants other people to contribute and have access to his recipes from any location. Eventually, he would like to have people contribute ideas and ingredients to his new recipes and perhaps even experiment with new methods of making drinks.

Git solves all of these problems! That’s why we’re going to use it in this training to manage Steve’s coffee recipe project.


3. Configure your local environment to start using Git

Git and the command line

Now that we have a good understanding of what Git is and how it manages our files between different statuses and directories, we need to make sure Git is installed before we can start using it.

Options depending on the operating system

On Mac:

  • Open Terminal (Mac’s default command line application)
  • Popular alternative: iTerm2 (iterm2.com) which offers features like split panes, auto-completion and better in-page search

On Windows:

  • Use the CMD window (Windows Command Prompt)
  • Or use Git BASH, which tends to be the more popular choice of the two options

On Linux:

  • You need a shell terminal

Check if Git is already installed

To check if Git is already installed, type in your command line:

git version

If Git is installed, you will get something like:

git version 2.37.1

Note for Mac users: You will probably see in parentheses after the Git version Apple Git followed by a number. If you see this, Apple has Git preinstalled on your computer with most likely an outdated version. With Git, there aren’t many major feature changes, so it’s generally acceptable.


Install Git

Regardless of what system you’re using, the best place to download Git is to navigate to git-scm.com. This is the official open source documentation for Git, and right on the home page you can see a prompt to download the latest version of Git.

This site detects the operating system you are using and will display the default download option for the system you are on.

Installing on Mac

The most common way is to use Homebrew, a free and open source software package management system that makes it easy to install software on Mac and Linux.

brew install git

Another option is to use MacPorts, another open source system used to install and upgrade software on your Mac.

Installation on Windows

Download the latest Git for Windows installer from git-scm.com, then go through the installation steps. The installation process will require some configuration, and Git BASH will be included in the installation.

Installing on Linux

On Debian/Ubuntu systems:

sudo apt-get install git

On Fedora/RHEL/CentOS systems:

sudo yum install git

Create a new Git repository

Now that Git is installed, let’s create a new Git repository. The repository represents your entire project. When you initialize Git for the first time in a project, you create a new Git repository inside that project called .git.

You can create a new empty project and initialize Git, or you can initialize Git with an existing project that already has a lot of content. Remember that wherever you initialize Git in a project, it will begin version control from that point in time.

Create a new project and initialize it with Git

# Créer un nouveau répertoire
mkdir demo

# Se déplacer dans ce répertoire
cd demo

# Initialiser un dépôt Git dans ce répertoire
git init

Git will return a message like:

Initialized empty Git repository in /Users/aarons/pluralsight/demo/.git/

Note on default branch

In newer versions of Git, you may see messages indicating that Git is looking to change from the default name master for the initial branch to the name main. Git will provide a git config command that you can run to make it a global setting:

git config --global init.defaultBranch main

Set Git configurations

Git has a config file in the .git directory. We can create Git configurations that will allow us to set certain settings when using Git.

There are two required Git configurations that you must set before you can make commits to the Git repository.

The three levels of Git configuration

Git configurations are done at three different levels:

  1. System: Configurations defined at the system level and applied to all users of a machine. Useful if several users share the same computer.

  2. Global: User-level settings that will apply to all Git repositories created under this user. These are the most common settings. Global configurations are stored in the ~/.gitconfig file.

  3. Local: Settings specific to a single Git repository that will only apply to that repository. Local configurations override global configurations. They are stored in the .git/config file of the repository.

Essential Configuration Commands

Show all global configurations:

git config --global --list

Show all configurations (system + global + local):

git config --list

Both system requirements

Before you can make commits, you must set your username and email address:

# Définir le nom d'utilisateur global
git config --global user.name "Votre Nom"

# Définir l'adresse email globale
git config --global user.email "votre.email@exemple.com"

This information will be attached to each commit you create, so others can see who made each change.

Set default branch

git config --global init.defaultBranch main

Show specific configuration

git config user.name
git config user.email

Set a default text editor

With Git installed and the requirements set, we are now ready to start using Git.

Common text editors

Here are some common text editors compatible with Git:

  • Visual Studio Code (recommended, cross-platform)
  • Sublime Text (recommended, cross-platform)
  • TextMate (Mac)
  • Espresso (Mac)
  • Notepad++ (Windows)
  • Vim (universal, available in most terminals)

Open VS Code from terminal

A useful feature is to use your terminal to open VS Code in exactly the directory you are in. To enable this feature:

  1. Open Visual Studio Code
  2. Open the Command palette (View menu → Command Palette, or Cmd+Shift+P on Mac / Ctrl+Shift+P on Windows/Linux)
  3. Search for “shell” and select Shell Command: Install ‘code’ command in PATH

Now from your terminal you can simply type:

code .

And Visual Studio Code will open directly in the current directory.

Set VS Code as default editor for Git

git config --global core.editor "code --wait"

4. Work in a local repository

Add Git to an existing project

Now that we’ve covered the main concepts of Git, the next best thing is to see these Git concepts and commands in action using Git in a project.

In Steve’s story, his Wired Brain Coffee Shop project is located in a directory called coffee-shop-recipes with three folders: hot-beverages, iced-beverages, and syrups.

Terminal navigation

# Afficher le contenu du répertoire courant
ls

# Se déplacer dans le projet de Steve
cd wired-brain-coffee

# Afficher le chemin complet du répertoire courant
pwd

# Afficher tous les fichiers, y compris les fichiers cachés
ls -a

Initialize Git in an existing project

git init

After initialization, check the repository status:

git status

Git will return:

  • There are no commits yet
  • There are untracked files (existing files in the project)
  • There is nothing added to the staging area to be committed

Add and track new files

After running git init on an existing project, Git tells us that there are untracked files. We need to tell Git to start tracking these files by adding them to the staging area to be committed.

Methods for adding files

When working in Git, there are often multiple ways to accomplish the same task. Here are the different ways to use git add:

# Ajouter un fichier spécifique
git add nom-du-fichier.md

# Ajouter un dossier entier
git add nom-du-dossier/

# Ajouter tous les fichiers non suivis/modifiés dans le répertoire courant
git add .

# Ajouter tous les fichiers non suivis/modifiés (alternative)
git add --all
git add -A

Check status after adding

git status

Files added to the staging area will now appear under the “Changes to be committed” section.

Make first commit

git commit -m "Initial commit - Add coffee shop recipe files"

After commit, git status will return that the working tree is clean (nothing to commit, working tree clean).


Make changes to files

Now that we have a Git repository and have made our first commit, let’s see how we can make changes to an already tracked file.

Scenario: Correct a file in Steve’s project

Steve wants to fix the caramel.md file in the syrups folder. The H1 title incorrectly says “Cinnamon Dolce Syrup” when it should say “Caramel Syrup”.

After making the modification in the editor and saving the file:

# Vérifier l'état - le fichier apparaîtra comme modifié dans le working directory
git status

# Ajouter le fichier modifié à la staging area
git add syrups/caramel.md

# Vérifier l'état - le fichier est maintenant dans la staging area
git status

# Commiter le changement
git commit -m "Fixed caramel file header"

Show differences between versions

The git diff command allows you to see exactly what changes have been made:

# Voir les modifications dans le working directory (non indexées)
git diff

# Voir les modifications dans la staging area (indexées, prêtes pour le commit)
git diff --staged

Create a new branch

So far everything has been done on the main branch, but since branches are an essential concept in Git, we should use multiple branches when committing changes to our project.

It is not recommended to make changes directly to the main branch. Of course, with Git you can always revert these changes, but branches allow you to work on new ideas and try new things without affecting your main branch.

Create and switch to a new branch

# Créer une nouvelle branche appelée "feature"
git branch feature

# Vérifier que nous sommes toujours sur main
git status

# Afficher toutes les branches locales (l'étoile * indique la branche courante)
git branch -a

# Basculer vers la branche feature
git checkout feature

# Alternative moderne (créer ET basculer en une seule commande)
git checkout -b feature

After running git checkout feature, Git will confirm:

Switched to branch 'feature'

Show different file statuses

Now that we are on the feature branch, Steve wants to make several changes. This illustrates Git’s flexibility to handle multiple changes in different states simultaneously.

Scenario with multiple files in different states

Steve makes two modifications:

  1. File 1 (café-latte.md): Change “1 cup of whole milk” to “1 cup of almond milk” → added to the staging area
  2. File 2 (frozen-mocha.md): Add a new step → remains in the working directory
# Après les modifications, vérifier l'état
git status
# Résultat :
# Changes to be committed: cafe-latte.md (staged)
# Changes not staged for commit: frozen-mocha.md (modified)

View change details

# Voir les modifications non indexées (working directory)
git diff

# Voir les modifications indexées (staging area)
git diff --staged

Note: The fact that Steve leaves for the weekend with one change in the staging area and one in the working directory perfectly illustrates the freedom that Git offers: you don’t have to commit everything at the same time. You can have work in progress at different stages and choose what you want to include in each commit.

The —patch option for partial commits

Git even allows you to add specific changes in the same file (specific lines):

git add -p nom-du-fichier

The -p (patch) option allows you to iterate through the changes in a file and select the specific line changes you want to add to the staging area while leaving the others behind in the working directory.


Merge one branch into another

After making several commits to different branches, it’s time to merge these changes.

Go back to the main branch and make a commit

# Retourner sur main
git checkout main

# Faire une modification et un commit sur main
# (pour créer une vraie histoire divergente)
git add .
git commit -m "Update recipe on main branch"

Merge feature branch into main

# S'assurer d'être sur la branche de destination (main)
git checkout main

# Fusionner la branche feature
git merge feature

If the merge succeeds without conflicts, Git will create a merge commit and display the files that have changed.


Show commit history

As you make more and more commits, it’s useful to see a history of your commits.

The git log command

Git provides a log command that will list the commit history of the Git repository. It includes all branches, and there are many options to define exactly what information you want to see (over 100 options available!).

git log is a display command, so all options are only for displaying information — they cannot be used to modify anything in your Git repository.

# Afficher l'historique complet
git log

Each commit shows:

  • The full commit ID (40 character SHA-1 hash)
  • The author of the commit
  • The date and timestamp of the commit
  • The commit message
  • Branch pointers (where main, feature, HEAD are located)

To exit the log, press Q.

Common git log options

# Afficher chaque commit sur une seule ligne (ID abrégé + message)
git log --oneline

# Afficher le graphe des branches
git log --oneline --graph

# Afficher le graphe de toutes les branches
git log --oneline --graph --all

# Afficher les N derniers commits
git log -5

# Afficher les modifications de chaque commit
git log -p

# Afficher un résumé des fichiers modifiés
git log --stat

# Afficher les commits depuis une date
git log --since="2023-01-01"

# Afficher les commits par un auteur spécifique
git log --author="Aaron Stewart"

# Rechercher dans les messages de commit
git log --grep="fix"

5. Work with others in a shared repository

Git on the network

This part is about working with Git on the network. The majority of people working with Git do so in a shared network environment.

A network Git repository is a centralized location where you and others can collaborate to share changes to the project in the form of Git commits.

The basic principle

Remember that one of the characteristics of Git is that it is local. This means that everything you do in Git is done locally on your computer. Even when you’re working in a shared Git repository on the network, but wait a minute — if we’re working in a shared repository, are we making changes directly on the server?

The answer is no. Everything in Git is done locally, then shared with the repository on the network for others to see and retrieve.

This centralized Git repository is just a copy of the same repository that you and others copy to work on on your own local machine. Essentially, you can think of this centralized Git repository on the network as a branch that you want to exchange commits with:

  • git push: Send your commits to the centralized repository
  • git fetch / git pull: Retrieve commits that others have pushed

The most popular options for hosting a Git repository on the network are:

  • GitHub: The most popular code hosting platform in the world
  • GitLab: Open source alternative to GitHub, can be self-hosted
  • Bitbucket: Atlassian solution, well integrated with Jira

These platforms are cloud hosting platforms that you can use as a central repository to collaborate with others on your Git projects.


Configure a remote repository on GitHub

Steve wants to put his project on the network so others can see it, collaborate and contribute to his project.

Create a new repository on GitHub

  1. Log in to your user profile on GitHub
  2. Navigate to the Repositories tab
  3. Click New to create a new repository
  4. Give it a unique name (ex: coffee-shop-recipes)
  5. Add a description (e.g.: “A place to store, create, and explore new coffee shop recipes”)
  6. Choose Public so others can see it
  7. Click Create repository

After creating the repository on GitHub, you will have a few options for linking your local repository. For an existing project with a commit history, use the following commands:

# Ajouter une connexion remote (lien vers le dépôt distant)
git remote add origin https://github.com/username/coffee-shop-recipes.git

# Vérifier les connexions remote configurées
git remote -v

You will see two connections to the same URL:

origin  https://github.com/username/coffee-shop-recipes.git (fetch)
origin  https://github.com/username/coffee-shop-recipes.git (push)

Why two connections? This concerns the two basic operations when working with remote repositories: git push (send changes) and git fetch/git pull (fetch changes).


Send local commits to the network

Now that we have linked our local repository to a repository on the network, let’s use the git push command.

Parse git push command

The complete command for the first push is:

git push -u origin main

Let’s break this command down:

  • git push: The Git command to send or push commits that we have locally and which are not yet represented in the remote Git repository on the network
  • -u (upstream): Configure an upstream — define where we send our commits to the remote repository. The -u option is needed the first time we want to push commits to a branch that we created locally but not yet to the remote repository. It tells the remote Git repository to create a remote tracking branch on the network that will link to our local branch.
  • origin: The name of the remote (shortcut for the URL of the remote repository)
  • main: The name of the branch we want to push

Once the upstream is configured, for the following pushes, you can simply use:

git push

Push a feature branch

# Première fois pour une nouvelle branche
git push -u origin feature

# Ensuite
git push

Clone a Git repository from the network

Now that we have our Git repository on the network, we can invite other team members to collaborate. But before they can collaborate, they need a copy of the project on their own computer.

By having this centralized Git repository on the network, each collaborator can simply clone Steve’s project from the network and then work on it locally.

How to clone a repository

  1. Navigate to the repository on GitHub
  2. Select the Code tab
  3. Copy the provided GitHub URL
  4. In the terminal, navigate to the location where you want the project to be copied
  5. Run the command:
git clone https://github.com/username/coffee-shop-recipes.git

Git will tell you that it is cloning the Git repository in the current directory, then return data telling you that the clone was successful.

Important: When cloning a project from GitHub, the remote connection to the origin is automatically configured, so any member who copies this project will automatically have this remote connection created.

# Après le clonage, vérifier la connexion remote
git remote -v

Retrieve and pull commits from the network

Now that we’ve seen how a team member can clone the repository from the network, make a change to a file in its local copy, and push that change to the Git repository on the network, it’s time for Steve to pull in the latest changes.

git pull — The most common command

The git pull command automatically pulls commits from the network that your local Git repository doesn’t have, then integrates them into the local versions of your branches.

git pull

git pull is essentially running two Git commands in one:

  1. git fetch: Fetch changes from the network
  2. git merge: Merges these changes into your local repository

git fetch — Fetch without merging

What if you wanted to see the changes first before Git automatically merges them into your local repository? This is where git fetch comes in.

# Récupérer les changements du réseau sans fusionner
git fetch

# Vérifier l'état après le fetch
git status
# Résultat : "Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded."
# Git vous dit que vous pouvez exécuter 'git pull' pour fusionner ce commit

# Voir les changements récupérés avant de les fusionner
git log origin/main

# Fusionner les changements récupérés
git pull

Introduction to merge strategies

When working with different branches, you may need to merge them together to bring commits from one branch into another.

There are different types of merge strategies that you can use with Git, and depending on how you want your commit history to appear, it may depend on the type of merge you are asking to perform.

Type 1: Fast-Forward Merge

This is the most basic and simple type of merge, and it can only be done if you have a linear commit path between the two branches.

Visualization:

Avant la fusion :
main:    A---B
              \
feature:       C---D

Après fast-forward merge de feature dans main :
main:    A---B---C---D

In this example, the feature branch is two commits ahead of main, but no other commits have been made to main to create a true divergent story. The commit history between these two branches is linear. So when we merge feature into main, Git can simply advance the main pointer to the last commit of feature.

git checkout main
git merge feature
# Git effectuera automatiquement un fast-forward merge

Type 2: Three-Way Merge

When the two branches have diverged (that is, commits have been made to both branches since the point of divergence), Git cannot do a fast-forward merge. Instead, it performs a three-way merge which creates a new merge commit.

Visualization:

Avant la fusion :
main:    A---B---E
              \
feature:       C---D

Après three-way merge de feature dans main :
main:    A---B---E---M (merge commit)
              \ /
feature:       C---D
git checkout main
git merge feature
# Git crée automatiquement un merge commit

Type 3: Rebase (advanced)

An advanced strategy that rewrites history to create a linear history:

git checkout feature
git rebase main

Warning: The rebase rewrites the commit history. It should not be used on shared branches or commits already pushed to a centralized repository. This can create problems for other employees.


6. Merge conflicts: what are they and how to resolve them?

Understanding merge conflicts

Unless you are working on a personal project alone, you will be working with others in a Git repository shared with dozens, hundreds, or even thousands of other people contributing to the same project.

Even following best practices, you can and probably experience a merge conflict.

What is a merge conflict?

A merge conflict occurs when there are conflicting changes introduced to the same content of the same file. This means:

  • Someone made changes to a file and pushed them to the centralized Git repository on the network
  • Then you make a different change to the same file contents
  • When you try to push your change, Git doesn’t know which change to accept

The 3 most common merge conflict situations

  1. Same line changed: More than one person changes the same line in a file and both try to merge the changes to the same branch.

  2. Deletion vs. modification: Someone deletes content in a file, but another person edits the same content.

  3. File deletion vs modification: Someone deletes a file entirely, but someone else has made changes to that same file.


Create merge conflict

To illustrate, here is how a conflict is created in Steve’s project:

Team member side

The team member makes changes to the white-mocha.md file:

  • Change “1 cup of 2% whole milk” to “1 cup of whole milk”
  • Update “2% milk” to “whole milk” in step 4
  • Add “And pairs perfectly with an almond croissant” to description
git status
git add hot-beverages/white-mocha.md
git commit -m "Update white mocha recipe"
git push

Steve’s side (at the same time, without having done git pull)

Steve also makes changes to the same white-mocha.md file:

  • It changes the same description line differently
git add hot-beverages/white-mocha.md
git commit -m "Update white mocha description"

Conflict occurs during git pull or git merge

When Steve tries to merge the team member’s changes:

git merge update-mocha
# CONFLICT (content): Merge conflict in hot-beverages/white-mocha.md
# Automatic merge failed; fix conflicts and then commit the result.

Resolve merge conflict

Git is telling us that there is a conflict with the content we are trying to merge into the main branch, and Git cannot complete the merge until we resolve this conflict.

Steps to resolve a conflict

# Voir plus d'informations sur le conflit
git status

Git gives us two options:

  1. Fix conflicts and then run git commit to confirm the changes
  2. Abort merge with git merge --abort

Git also pointed out the exact file(s) that had a conflict and moved them back into our working directory.

Conflict markers

When opening the conflicting file in the text editor, you will see merge conflict markers:

<<<<<<< HEAD
Contenu de la branche courante (HEAD / main)
=======
Contenu de la branche entrante (update-mocha)
>>>>>>> update-mocha
  • The top section (between <<<<<<< HEAD and =======) is called current change — this is the content in conflict on the current branch (main in our case)
  • The bottom section (between ======= and >>>>>>> update-mocha) is called incoming change — this is the conflicting content on the branch we are trying to merge

How to solve

  1. Decide what you want to keep: the current change, the incoming change, both, or a combination
  2. Remove conflict markers (<<<<<<<, =======, >>>>>>>) and any content you don’t want
  3. Save the file

In VS Code, you have practical buttons:

  • Accept Current Change: Keep only the contents of HEAD
  • Accept Incoming Change: Keep only incoming content
  • Accept Both Changes: Keep both contents
  • Compare Changes: See the differences side by side

Finalize resolution

# Après avoir résolu tous les conflits dans le fichier
git add hot-beverages/white-mocha.md

# Commiter pour finaliser la résolution du conflit
git commit -m "Resolve merge conflict in white mocha recipe"

Git automatically creates a merge commit message, but you can customize it.


Prevent merge conflicts

Knowing how to resolve merge conflicts is great, but there are best practices to follow that will help reduce the number of merge conflicts you and your team experience.

1. Standardize your formatting

Many conflicts arise simply because of formatting mismatches — extra spaces, different coding styles. You can apply code formatters and linting rules to ensure your team is aware of these issues and to reduce the number of these types of merge conflicts.

2. Make small and frequent commits

Taking weeks to make changes to a branch and adding lots of changes to lots of files is almost like asking for merge conflicts. It’s generally best to make small and direct changes and then merge them into your main branch frequently. Don’t wait long periods of time to merge changes if you can avoid it.

3. Communicate and pay attention

Talk to each other and know who is working on what. If multiple people are making changes to the same files, work together and communicate often. This is a great way to help reduce the number of merge conflicts within your team.


7. How to modify and correct your commits

Fix commit error with git amend

So far we have made a lot of commits. These commit IDs are really important and are what Git uses to track and manage each commit snapshot.

What makes up a commit ID

Git uses the following to create each commit ID:

  • The author
  • The timestamp
  • The commit message
  • The actual changes made
  • Even commits that precede this commit

All of these and more are used when Git creates the commit ID. So, as you can imagine, editing an existing commit will change this ID.

The general rule for modifying history

If your commits exist only locally and you haven’t pushed them to a centralized Git repository that others use, you are free to modify these commits as much as you want.

If you have already pushed commits that others base their work on, changing the history will create a broken history.

Using git amend

The git commit --amend command allows you to modify the latest commit (only).

Common use cases:

  1. Fix a commit message:
git commit --amend -m "Nouveau message de commit corrigé"
  1. Add forgotten files to last commit:
# Ajouter le fichier oublié à la staging area
git add fichier-oublie.md

# Amender le dernier commit (inclure les nouveaux fichiers indexés)
git commit --amend --no-edit
# --no-edit conserve le même message de commit
  1. Edit message AND add files:
git add fichier-oublie.md
git commit --amend -m "Nouveau message incluant le fichier oublié"

Note: git amend creates a completely new commit replacing the last one. The old commit is removed from visible history, although it is still accessible via git reflog.


Rewrite history with git reset

Sometimes we need something more robust — something we can use to reset some or even all of our files to look like they did at a different time in history.

The three git reset options

Git provides three options available with git reset:

Option 1: git reset —soft

This type of reset will take a commit from our history and put it back in our staging area. This is useful if you need to group commits or alter something in the changes indexed for the commit.

# Réinitialiser les 2 derniers commits vers la staging area
git reset --soft HEAD~2

After this command, git status will show the changes in the staging area, ready to be recommitted.

Option 2: git reset (—mixed, the default option)

This is the default option for reset. It will take a commit from history and place it in your working directory. This is if you want to take these changes back to the drawing board and make modifications before indexing them again.

# Réinitialiser les 2 derniers commits vers le working directory (option par défaut)
git reset HEAD~2
# Équivalent à :
git reset --mixed HEAD~2

After this command, git status will show the files in the working directory (not staged for commit).

Option 3: git reset —hard

⚠️ Warning: This is a destructive command! This type of reset will take a commit from history and throw it in the trash — almost as if it never happened. Double-check your work before using this type of reset.

# Supprimer définitivement les 2 derniers commits
git reset --hard HEAD~2

After this command, the commits and their changes disappear — they are neither in the staging area nor in the working directory.

Syntaxes for specifying the reset point

# Réinitialiser jusqu'à N commits en arrière
git reset HEAD~1   # Réinitialiser le dernier commit
git reset HEAD~3   # Réinitialiser les 3 derniers commits

# Réinitialiser jusqu'à un commit spécifique par son ID
git reset abc1234

# Réinitialiser jusqu'au commit parent du commit actuel
git reset HEAD^

Summary table of git reset options

OptionsStaging AreaWorking DirectoryHistory
--softKeep changes ✓UnchangedCommit deleted
--mixed (default)EmptyKeep changes ✓Commit deleted
--hardEmptyRemove changes ✗Commit deleted

Recover deleted history with git reflog

After using git reset --hard to delete commits containing files 5, 6 and 7, Steve realizes he made a big mistake. He doesn’t want files 6 or 7, but he really wants file 5 back.

Git provides a way to recover commits, even if you deleted them with a git reset.

git reflog — The log of all HEAD positions

Similar to git log which tracks our commits, Git has a log which tracks wherever HEAD has been, and it is called the git reflog.

Reflog limitations

  • Local only: The reflog is not pushed to the remote Git repository and only includes your local history. You can’t see the reflog of someone else’s commits.
  • Limited duration: By default, these commits are only displayed in the reflog for 90 days. After 90 days, these commits are completely lost.

Using reflog to retrieve a commit

# Afficher le reflog
git reflog

The reflog shows output similar to git log --oneline. This is a history of where HEAD is, so we can find where we added file5 and then copy that commit ID.

Revert a commit with git cherry-pick

# Copier l'ID de commit du fichier que vous voulez restaurer depuis le reflog
# Exemple : abc1234

# Restaurer ce commit directement dans l'historique des commits
git cherry-pick abc1234

git cherry-pick allows you to take a commit from the reflog and place it directly in the commit history — not in the working directory or the staging area, but directly in the history.

Git will return output similar to when you make a normal commit, with the abbreviated commit ID and commit message.


Introduction to Git workflows

At this point, we have covered the main concepts and fundamentals of Git. These concepts and fundamentals will hold true in any Git project you work on.

It doesn’t matter if you’re working on a personal project alone, just on your local machine, or if you’re contributing to a centralized Git repository on the network with thousands of other contributors. The process of adding files from the working directory to the staging area and then committing those changes is a fundamental concept of how Git works.

What may change is the workflows and how you integrate your changes into the Git repository. Depending on the needs of the project, these workflows can be simple or a little more involved.

Pull requests in the workflow

Depending on the code hosting platform you use, there are collaboration features like pull requests (or merge requests on GitLab) that you can integrate into your Git workflow that will improve the way you review, discuss, and secure your Git projects.


Basic Workflow

The easiest way to use Git is to use a Basic Workflow.

Description

This workflow uses the default main branch as the only branch that contributors use to make their changes.

[Dépôt centralisé sur le réseau]
    |         ^
  clone/pull  |push
    |         |
[Copie locale 1]   [Copie locale 2]   [Copie locale 3]

Each contributor can:

  1. Clone the repository
  2. Work locally on the project
  3. Push their commits to the central repository — all on the main branch

Advantages

  • Extremely simple to understand and use
  • Perfect for personal projects or projects with very few contributors

Disadvantages and limitations

  • Can quickly become problematic if more than one contributor wants to work on different features within the project
  • Having everyone contribute to the main branch is a great way to run into a lot of merge conflicts
  • Does not provide much flexibility to build features without affecting the production-ready project on the main branch

This workflow works well for simple personal projects where you are the only contributor. This was the case for Steve at first, but with the addition of more contributors, it’s best to move to a workflow that better supports divergent history.


Feature Branch Workflow

The Feature Branch Workflow takes the basic workflow, but instead of committing directly to the main branch, contributors create feature branches from main when they want to work on new features or try new ideas.

Description

main:      A---B-----------M (merge commit)
                \          /
feature-login:   C---D---E

With this workflow:

  • Everything in the main branch is deployable
  • When you want to work on a new feature, you create a new feature branch from main
  • You can also create feature branches from other feature branches

Advantages

  • Offers feature branching, but not too complex
  • Workflow adapted to continuous integration and continuous delivery (CI/CD)
  • Good option if you only need to maintain a single version in production
  • Allows team members to better review code changes in feature branches before they are merged into the main branch

Disadvantages

  • With these feature branches merging into main, the only production version of the project, it is easy for errors to end up in production
  • Not a good option if you need release branches or multiple versions of the project in a production environment

If you want feature branches and only need one version of the project deployable to production, this workflow could be a good option. But if you need these features, but also need to better secure the main branch with release and develop branches, you will probably want the next workflow: the Git Flow.


Git Flow

The Git Flow takes the Feature Branch Workflow and adds some elements to it. This is the most common workflow you’ll encounter when working with Git repositories in larger teams.

Branch structure in Git Flow

main:      ●-----------●-----------● (versions en production)
           |           |           |
release:   ●---●---●   ●---●---●
           |           |
develop:   ●---●---●---●---●---●---● (pré-production)
               |       |   |
feature-A:     ●---●   |   |
                   |   |   |
feature-B:         ●---●   |
                           |
hotfix:                    ●---●

Main branches

BranchRole
mainProduction version of the project — still stable and deployable
developPre-production branch — changes from feature branches are merged here
feature/*Branches to work on new features
release/*Branches of preparing a release
hotfix/*Branches for urgent fixes in production

Description

The main difference with the Feature Branch Workflow is that contributors branch from develop and not from main.

The develop branch is a pre-production environment, so changes merged from the feature branches can be reviewed and tested in this pre-production state before being merged into the main branch, which is the production version of the project.

This adds that extra level of review and testing that helps eliminate errors and buggy code from the main branch.

Advantages

  • Very popular, especially in the open source community
  • Project maintainers can better review and approve code going into release or develop branches before being merged into main
  • Works well with established products and multiple versions of the project
  • Adds that extra layer of review, significantly reducing the amount of errors going into production

Disadvantages

  • Sometimes this workflow can slow things down — it can take time to review and push to production
  • Going through all these different branches can also be confusing for new team members contributing to a workflow and knowing all the different steps to merge their code
  • With all these extra layers of branch merging, you may encounter merge conflicts more often

How these workflows are documented and communicated across the team makes all the difference when working in a large project environment.


9. Summary and next steps

Summary

Understanding the fundamentals of Git is a great start to working and contributing to a Git repository. And if you don’t consider yourself a developer, most companies these days are turning to Git repositories to better manage, secure, and innovate their projects and products.

What you learned in this training

  1. Thinking in Git: Understand the characteristics of Git, the stages of a file, and the three main directories of Git.

  2. Set up your Git environment: Install Git using the command line, basic command line navigation, and configure some Git configurations and your text editor.

  3. Working in a local project (Steve’s Wired Brain Coffee Shop project):

  • Add new files to a Git project
  • Make changes and commit these changes to history
  • Show these changes using the commit log
  • Show changes in different file states using git diff command
  • Merge these changes into the main branch
  1. Working with a centralized repository on the network:
  • Set up a centralized Git repository on the network so other team members can contribute
  • Remote branches and how to interact with remote Git repositories with commands like git push, git clone, git fetch, and git pull
  1. Merge strategies: Fast-forward merges and three-way merges, and a brief introduction to rebasing.

  2. Merge conflicts: How they arise, how to resolve them with conflict markers, and best practices to prevent them.

  3. Edit commit history:

  • git amend to modify the last commit
  • git reset with its three options (soft, mixed, hard)
  • git reflog to recover deleted commits
  • git cherry-pick to restore a specific commit
  1. Popular team workflows: Basic Workflow, Feature Branch Workflow, and Git Flow.

Next steps

Now that you have a solid understanding of these fundamentals, expanding your knowledge with a deeper dive into Git is a great next step.

Suggested further developments

  1. Understanding Git’s internal storage: How Git stores and manages your commits in depth — the objects, the blobs, the trees, the refs, and exactly what goes into each commit ID.

  2. Advanced Git Commands: There are so many other commands you can use. They are separated into two categories:

  • Porcelain commands: High-level commands (those we saw in this training)
  • Plumbing commands: Low level commands that do what porcelain commands do, but at a lower level
  1. Git Aliases: There’s a lot more you can do with Git configurations by creating aliases that you can use for those long Git commands:

    # Exemple d'alias Git
    git config --global alias.st status
    git config --global alias.co checkout
    git config --global alias.br branch
    git config --global alias.cm "commit -m"
    git config --global alias.lg "log --oneline --graph --all"
    
  2. Customize the command prompt: Learn how to customize your command prompt to display the current Git branch and other useful information.

  3. Visual tools for Git: Tools like GitKraken, Sourcetree, or VS Code extensions like GitLens can make viewing your Git history much more intuitive.

  4. The official Git documentation: Navigate to git-scm.com/docs for complete documentation of all Git commands.

Resources mentioned in the training

  • git-scm.com: Official Git documentation
  • iterm2.com: Enhanced Terminal for Mac
  • Homebrew: Package manager for Mac/Linux
  • The GitHub repository used in training for Steve’s Wired Brain Coffee Shop project, which also includes a bash script to create the files used when learning git reset

10. Appendix: Git Commands Quick Reference

Basic commands

# Initialiser un nouveau dépôt
git init

# Vérifier l'état du dépôt
git status

# Ajouter des fichiers à la staging area
git add <fichier>         # Un fichier spécifique
git add .                 # Tout dans le répertoire courant
git add -A                # Tous les fichiers (équivalent à git add --all)
git add -p <fichier>      # Mode interactif (patch) pour ajouter des lignes spécifiques

# Commiter les changements
git commit -m "Message de commit"
git commit --amend -m "Corriger le message du dernier commit"
git commit --amend --no-edit  # Amender sans changer le message

# Afficher les différences
git diff                  # Différences dans le working directory
git diff --staged         # Différences dans la staging area

# Afficher l'historique
git log                   # Historique complet
git log --oneline         # Historique simplifié
git log --oneline --graph --all  # Graphe de toutes les branches
git log -5                # Les 5 derniers commits

Branch commands

# Lister les branches
git branch                # Branches locales
git branch -a             # Toutes les branches (locales + distantes)

# Créer une branche
git branch <nom>          # Créer sans basculer
git checkout -b <nom>     # Créer ET basculer

# Basculer de branche
git checkout <nom>

# Fusionner une branche
git merge <nom-branche>

# Supprimer une branche
git branch -d <nom>       # Suppression sécurisée (refuse si non fusionnée)
git branch -D <nom>       # Forcer la suppression

Network commands (remote)

# Gérer les remotes
git remote -v                        # Lister les remotes
git remote add origin <url>          # Ajouter un remote

# Cloner un dépôt
git clone <url>

# Envoyer des commits
git push -u origin main              # Premier push (configure l'upstream)
git push                             # Pushes suivants

# Récupérer des commits
git fetch                            # Récupérer sans fusionner
git pull                             # Récupérer ET fusionner (fetch + merge)

Cancel commands

# Modifier le dernier commit
git commit --amend -m "Nouveau message"

# Réinitialiser des commits
git reset --soft HEAD~N   # N commits vers la staging area
git reset HEAD~N          # N commits vers le working directory (défaut --mixed)
git reset --hard HEAD~N   # Supprimer définitivement N commits

# Voir l'historique de HEAD
git reflog

# Restaurer un commit supprimé
git cherry-pick <commit-id>

# Créer un commit d'annulation (sûr pour les dépôts partagés)
git revert <commit-id>

Configuration commands

# Voir la configuration
git config --list
git config --global --list

# Configurer l'identité (requis)
git config --global user.name "Votre Nom"
git config --global user.email "email@exemple.com"

# Configurer la branche par défaut
git config --global init.defaultBranch main

# Configurer l'éditeur
git config --global core.editor "code --wait"

# Créer des alias
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"

Search Terms

git · fundamentals · ci/cd · devops · merge · branch · commands · repository · commit · conflict · reset · local · command · commits · default · history · network · pull · steve · configuration · option · options · reflog · set

Interested in this course?

Contact us to book it or get a custom training plan for your team.