Complete documentation in French
Table of Contents
- The importance of a clean history
- Anatomy of a good commit
- Atomic commits
- Consistent commits
- Incremental commits
- Documented commits
- Private History vs. public
- The concept of reachability
- When did this merger take place?
- Commit vs. Patches
- When was this code changed?
- Who made this change?
- The power of the Git branching model
- The different types of branches
- The different ways to merge
- Resolve conflicts
- Bear vs. Theirs
- Reuse saved resolutions (rerere)
1. Course Overview
Hello everyone. My name is Enrico Campidoglio. Welcome to my Git Tips and Tricks course. I am an independent programmer and trainer. And like you, I use Git every day to manage the history of the code I’m working on. Over time, I developed a deep appreciation for Git’s design philosophy.
Contrary to what is often believed, Git is not an obscure and excessively complex tool. It’s more like a Swiss army knife filled with small, specialized tools, each designed to do a specific thing and do it well. Some of these tools are obvious and widely used, while others are less visible or even hidden, and their value often goes unnoticed. The key to mastering Git is knowing how to unlock and use all of these tools to improve your workflow.
In this course, that’s exactly what we’re going to do. We’ll unfold the Swiss army knife of Git together and explore how to harness its full potential to improve your daily development workflow.
Main topics covered
- Boost your productivity with Git command line
- Maintain a clean and organized history of your code
- Compare the different branching and merging strategies
- Fix errors and recover lost commits
- Track bugs through your project history
By the end of the course, you will have a solid understanding of Git’s design philosophy and be able to combine its tools to streamline your workflow, complete tasks more efficiently, and manage your projects more productively.
2. Adopt command line
Why this course?
If you’ve been using Git for a while, you probably know how to use it like any other visual version control system. You commit files, view change history, maybe even create and merge branches. But you’ve probably also heard that Git isn’t like other version control systems — it’s more powerful.
This certainly sounds great, but what does it mean in practice? This course will teach you where this power lies. You’ll learn how to take advantage of Git’s advanced, and therefore lesser-known, features to help improve your daily workflow.
CLI vs. MISTLETOE
Throughout this course, we will interact with Git entirely from the command line. If you feel more comfortable using a graphical user interface (GUI), you can certainly use one alongside the command line. However, it is highly recommended to make the command line your primary tool when using Git.
Why?
GUIs, no matter how well designed, always impose some limitation on what you can or cannot do. In general, people tend to fall into two camps when it comes to how they prefer to interact with computers:
- Advocates of the CLI (Command-Line Interface): those who, having the choice, will always use a command-line interface.
- Supporters of the GUI (Graphical User Interface): those who prefer a graphical interface.
The preference between the two is largely a matter of taste. However, it is undeniable that for certain tasks, one is more suitable than the other.
For example, it would be slow and inconvenient to browse the web with a text-based browser like LYNX. Likewise, when it comes to Git, the command line is much more efficient than any GUI.
If you think of Git’s commands and options as a Domain-Specific Language (DSL) — a language that allows you to manipulate the history of your source code — it becomes clear that any attempt to fit it into a GUI with menus and toolbars is bound to be limited.
Tools
Using Git from a command terminal doesn’t mean we have to sacrifice usability. There are a few utilities designed specifically to make Git easier to use from the command line:
- They enrich the command prompt with updated repository information.
- Most also provide autocomplete, which reduces typing.
Additionally, throughout the course we will use a real-time graphical representation of our Git repositories. Each time we execute a command, the graph will show how it affected the underlying history. This type of visualization really helps understand how controls work at their fundamental level.
Prerequisites:
- Git installed (version 1.8.0 or higher)
Git fundamentals
One of the common complaints about Git is that it is too complicated. You may have heard someone say that “Git is hard” or even “Git is harder for me than programming”. These complaints are understandable. Git can indeed be quite intimidating at first, with its scary-sounding commands and huge set of options and settings.
However, beneath this unwelcoming surface, the foundations of Git are actually very simple. So simple, in fact, that we can summarize them using three basic concepts:
- Commit
- Snapshots
- References
The Commits
Every time we commit changes, Git creates what is called a commit object. The commit contains information about:
- Its author
- The timestamp of its creation
- And, more importantly, a reference to the commit that precedes it: its parent
Snapshots
This snapshot represents the state of the directories and files in the repository at the time the commit was created. Internally, Git represents each directory with an object called a tree. Below a tree, there may be other trees or the actual files, which are called blobs.
You can directly point to any commit, tree or blob by its unique identifier, which consists of the SHA1 hash calculated from the contents of the object.
References
Although having these IDs is sometimes very handy, using them all the time would quickly become tedious. This is why Git offers a better way to refer to commits: using references. A reference is simply a name that points to a certain commit. It can be considered as a symbolic link or a bookmark.
There are three types of references:
| Type | Description |
|---|---|
| Tag | A fixed reference to a specific commit — never changes. Used to mark the commit associated with a certain software version. |
| Branch | A reference to the last commit in a history line. Every time we create a new commit, the branch reference advances. |
| HEAD | A special reference that always points to the currently checked out commit. This is how Git knows which branch is active. |
3. Élever votre expérience en ligne de commande
In this module we will see how to work effectively with Git from the command line. We’ll look at a few utilities designed specifically to make it easier to use, then see how to do more with less typing using aliases, and finally, we’ll explore some interesting ways to view the contents and history of our repositories without ever leaving the command line.
Command line utilities
The choice of which utility to use depends primarily on your operating system.
For Windows: posh-git
If you are using Windows, your best option is to use Git from PowerShell using a module called posh-git.
Install from GitHub:
# Cloner le dépôt posh-git
git clone https://github.com/dahlbyk/posh-git.git
# Exécuter le script d'installation
./install.ps1
Installation with PowerShellGet (if PSGet is installed):
Install-Module posh-git
Once posh-git is installed, whenever you enter a directory containing a Git repository, posh-git automatically enriches the command prompt with useful information:
- The name of the current branch
- The number of files added, modified and deleted, both in the working directory and in the index (staging area)
For Linux/macOS: Bash with autocompletion
If you are using Bash on Linux or macOS and only want autocompletion, there is a simple script in the Git source code. Just download it and add it to your Bash profile:
# Télécharger le script de complétion
curl -o ~/.git-completion.bash https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash
# Ajouter à .bash_profile
echo "source ~/.git-completion.bash" >> ~/.bash_profile
For advanced Linux/macOS: Oh My Zsh
If you prefer something more visually appealing, it is recommended to replace Bash with the Z shell (Zsh) and install a set of utilities called Oh My Zsh. This environment offers a very visually pleasing interface with Git information integrated into the command prompt.
Aliases
Sometimes, even without autocomplete, you just can’t type fast enough. For these situations, having short aliases for the most common Git commands can be very useful.
Create a simple alias
# Créer un alias "st" pour "status"
git config alias.st status
# Utilisation
git st
Aliases are stored in a dedicated section of the Git configuration file. This is what it looks like in .gitconfig:
[alias]
st = status
Alias scope
As with any other parameter, you can define aliases that apply:
- Only for current repository (no option)
- For all repositories of logged in user (
--global) - For the entire system (
--system)
# Alias global (recommandé)
git config --global alias.st status
Alias with combined options
# Version plus utile : status en mode court
git config --global alias.st "status --short"
Alias for quick commit
# Committer tous les fichiers modifiés avec un message
git config --global alias.ca "commit --all --message"
# Utilisation
git ca "Mon message de commit"
Advanced aliases with shell functions
Aliases can contain an entire sequence of commands and even accept parameters. For example, a very useful alias called dm (for “delete merged”):
git config --global alias.dm '!git branch --merged | grep -v "^\*\|main\|master" | xargs git branch -d'
Explanation of this alias:
!tells Git that the following should be interpreted as a shell commandgit branch --mergedlists branches that have already been merged into the current branchgrep -v "^\*\|main\|master"excludes current branch (*),mainandmasterxargs git branch -dremoves all remaining branches
This alias allows you to quickly delete all local branches that have already been merged into the current branch.
Aesthetic logs
When we want to view the history of the current branch, we use git log. This way of visualizing a sequence of commits is correct, but we can do better.
Format log on one line per commit
git log --pretty=oneline
It’s definitely easier to read, but it’s missing some important information — just the SHA-1 hash and messages.
Custom size
The git log command supports an option that allows you to format the list of commits in different ways. Here is an example of a custom format:
git log --pretty=format:"%h %d %s %cr %an"
Explanation of placeholders:
| Placeholder | Description |
|---|---|
%h | Abbreviated commit hash |
%d | Any reference currently pointing to the commit (branches, tags) |
%s | First line of the commit message (the subject) |
%cr | Timestamp relative to now (ex: “3 days ago”) |
%an | Commit author name |
A complete list of all available placeholders is available in the official Git documentation.
Add colors
git log --pretty=format:"%C(yellow)%h%Creset %C(blue)%d%Creset %s %C(green)%cr%Creset %C(red)%an%Creset"
Add branch graph
git log --pretty=format:"%C(yellow)%h%Creset %C(blue)%d%Creset %s %C(green)%cr%Creset" --graph
Create alias lg (graphic log)
Since we don’t want to type all of this every time, let’s create an alias:
git config --global alias.lg "log --pretty=format:'%C(yellow)%h%Creset %C(blue)%d%Creset %s %C(green)%cr%Creset %C(red)%an%Creset' --graph"
Usage:
git lg
Aesthetic differences
Besides the history, we will just as often look at the contents of our working directory, the index, and specific commits. To do this, we use the diff command.
The standard diff command
git diff
What we see here are the changes currently in our working directory, displayed in unified diff format — something common.
The default pager: less
By default, Git redirects the output of commands that might produce more text than would fit on a screen to a program called less to provide pagination. With less you can:
- Scroll with
K(up) andJ(down) keys - Return to command prompt by pressing
Q
Use Delta as a pager
Git has a core.pager setting that allows you to configure which program to use for paging. Delta is an excellent diff program:
- Cleaner presentation
- Keyboard navigation
- Syntax highlighting for a wide variety of programming languages
- Cross-platform
# Installer Delta (exemple avec Homebrew sur macOS)
brew install git-delta
# Configurer Git pour utiliser Delta
git config --global core.pager delta
# Configuration optionnelle dans .gitconfig
git config --global delta.line-numbers true
git config --global delta.syntax-theme "Monokai Extended"
Diffs with word highlighting
Depending on the unified diff format, a line of text is always either added or deleted. Even if only part of a line is changed, the entire line will be shown as deleted and re-added. To see only the words that have changed:
git diff --word-diff
Inspect commits
There are several ways to examine the changes introduced by a specific commit.
The show command
# Voir le dernier commit
git show
# Voir un commit spécifique par référence
git show HEAD~2
# Voir avec un format personnalisé
git show --pretty=format:"%h %d %s %cr %an" HEAD
Structure of git show output:
- The first section contains information about the commit object itself: its SHA-1 hash, author, timestamp, and message
- The second section shows the difference between the snapshot referenced by the commit and the one referenced by its parent
Alias so for show object
git config --global alias.so "show --pretty=format:'%C(yellow)%h%Creset %C(blue)%d%Creset%n%s%n%n%b' --stat"
Show only metadata without the diff
git show --pretty=format:"%h %d %s %cr %an" --no-patch HEAD
Show with summary of modified files
git show --stat HEAD
Show commit messages in Markdown with glow
With Markdown becoming the standard markup language for the web, many open source projects write their commit messages in Markdown. The glow tool can display formatted Markdown content directly in the terminal:
# Installer glow (exemple macOS)
brew install glow
# Alias pour afficher un commit avec rendu Markdown
git config --global alias.show-md "!f() { git show --pretty=format:'%s%n%n%b' --no-patch ${1:-HEAD} | glow -; }; f"
4. Maintenir un historique propre
In this module, we’ll look at how to leverage Git’s unique features to create beautiful commits that respect the history of our source code.
The importance of a clean history
“Study the past if you want to define the future” said the ancient Chinese philosopher Confucius.
As with many other things in life, the way you move forward in a codebase starts with understanding how things got there in the first place. This valuable information is captured by the version control system. But there is a downside: merely storing the history of our code base in a version control system does not guarantee that we will be able to derive value from it.
- If history is complicated, ambiguous, and poorly documented, it becomes a black box, keeping this valuable information locked and inaccessible.
- If, on the contrary, it is clear and easy to follow, it becomes the key to understanding the decisions made by the programmers who preceded us.
The Git designers understood this. That’s why they built special features into Git to give us a fair chance of maintaining a nice-looking history.
Anatomy of a good commit
A good commit generally has four recognizable traits. It is ACID:
| Quality | English | Description |
|---|---|---|
| Atomic | Atomic | The commit is self-contained — semantically related changes should not be split across multiple commits |
| Consistent | Consistent | Each commit must leave the code in a consistent state (compilable, passing tests) |
| Incremental | Incremental | Commits should build on each other logically |
| Documented | Documented | A good commit message explains what the patch does |
Atomic
A commit must be atomic, i.e. standalone. This means that we should not split semantically related changes across multiple commits. For example, if we were to rename a function, we would commit the renamed function, along with all references where the function was used, in a single commit.
Related to atomicity is the concept of thematic consistency: just as we should avoid splitting up thematically related changes, we should also ensure that each commit represents a single logical change. Renaming a function (and all its references) represents one commit, fixing a bug represents another.
Consistent
Each commit must leave the code in a consistent state. At a minimum, the code should compile without errors and broken tests. The reason for this requirement is that it should be possible to apply individual commits to the working directory and immediately be able to build on them without having to deal with compilation errors or failing tests first.
Incremental
A codebase evolves through a sequence of self-contained, logically consistent changes that build on each other incrementally. This is why the order in which commits appear in the history line is important.
For example, if we were to build a feature, the order of our commits would reflect the evolution of the code as the feature was implemented. The order of commits should not be arbitrary, but rather explanatory — it should clearly document the programmer’s thought process.
Documented
A good commit requires a well-formed commit message that explains what the patch does to the codebase.
Atomic Commits
A single consistent change — that’s all a commit should be. It should represent some type of change, whether it’s documentation, a refactoring, a bug fix, or a new feature.
Respecting this rule with Git is easier than with any other version control system thanks to the index (also called staging area).
The index (Staging Area)
The index is one of Git’s most distinctive features. According to programmers who were involved in the early days of Git:
“It became very quickly apparent that it was very useful to be able to trust
git commit, having prepared the index with what should and should not be included in the commit, so as not to pick up debugs that you keep in the working tree.”
This is exactly what the index is for.
Practical example
Suppose we have two modified files in our working directory:
- One that modifies a word in a documentation file
- Another one that modifies code
We don’t want both in the same commit (not atomic). Thanks to the index:
# Ajouter seulement le fichier de documentation à l'index
git add README.md
# Voir ce qui est dans l'index (ce qui sera commité)
git diff --staged
# Voir ce qui est seulement dans le répertoire de travail
git diff
# Créer le premier commit (documentation uniquement)
git commit -m "Mise à jour de la documentation"
# Ajouter le fichier de code à l'index
git add calculator.c
# Créer le deuxième commit (code uniquement)
git commit -m "Refactorisation du module calculatrice"
Partial staging with -p
Git even allows you to stage only part of a file with the patch (-p) option:
git add -p calculator.c
This command presents each “hunk” (block of changes) interactively and asks you if you want to stage it:
y— stage this hunkn— don’t stage this hunks— split this hunk into smaller hunkse— manually edit this hunk?— show help
Consistent commits
Once we’ve decided which files will be part of our next commit, it’s useful to check that what’s in the index is consistent.
Checking white space
As programmers, one of the first things we check for is unintentional white space:
# Voir les espaces blancs invalides en diff
git diff --staged
# Vérifier spécifiquement les espaces blancs
git diff --check
Git will automatically highlight any invalid whitespace in the patch output. The --check option is particularly useful in scripts because it exits with a non-zero exit code if it finds one.
White space configuration
The location considered invalid for whitespace is controlled by the core.whitespace configuration option:
# Voir les paramètres actuels
git config core.whitespace
# Configurer pour vérifier les tabulations dans l'indentation
git config --global core.whitespace "tab-in-indent"
Options available for core.whitespace:
trailing-space— trailing space (enabled by default)space-before-tab— space before a tab (enabled by default)indent-with-non-tab— indentation with spaces instead of tabs (enabled by default)tab-in-indent— tab in indentation (disabled by default)cr-at-eol— carriage return at end of line (disabled by default)
# Exemple : assurer l'indentation avec des espaces uniquement
git config --global core.whitespace "tab-in-indent,trailing-space"
Use stash to check index alone
Once you are satisfied with the contents of the index, it is time to verify that the code actually works. But how do you check the contents of the index alone, separate from all other changes in the working directory?
We can do this using stash. The stash is a storage area where we can temporarily put unfinished work that we want to remove from the working directory:
# Garder les changements stagés, mettre les non-stagés dans le stash
git stash --keep-index
# Maintenant, seulement les changements de l'index sont dans le répertoire de travail
# Exécuter les tests...
npm test
# ... ou compiler
make
# Récupérer les changements cachés
git stash pop
Incremental commits
It’s important to leave a trail of commits that shows our thought process as we moved through the code base.
Example of incremental sequence
To add new functionality, a sequence of commits could be:
- Commit 1: Refactoring that prepares the ground for the new functionality
- Commit 2: Writing a failing acceptance test (skipped/skipped)
- Commit 3: Actual implementation of the feature
Note that each commit should leave the codebase in a consistent state. Acceptance testing is skipped in step 2 to communicate how the feature is supposed to work without breaking the test suite.
Interactive rebase to clean local history
However, keeping a tight sequence of commits during development is very difficult. For most of us, the creative process is a little more erratic, fraught with mistakes, experiments, and changes in direction.
Fortunately, Git, being a distributed version control system, allows us to separate the history that only exists on our local machines from that which we share publicly. As long as we haven’t shared our commits with anyone else, we are free to change their content, messages, and order.
A common way to clean up our local history before publishing it is to do an interactive rebase:
# Démarrer un rebase interactif pour les 4 derniers commits
git rebase -i HEAD~4
This opens the editor with a list of commits in the specified range, providing a series of actions we can take on each:
pick abc1234 Premier commit
pick def5678 Deuxième commit
pick ghi9012 Troisième commit
pick jkl3456 Quatrième commit
# Commandes disponibles :
# p, pick = utiliser le commit tel quel
# r, reword = utiliser le commit, mais éditer son message
# e, edit = utiliser le commit, mais s'arrêter pour modifier
# s, squash = fusionner avec le commit précédent
# f, fixup = comme squash, mais supprimer le message de ce commit
# d, drop = supprimer ce commit
Examples of actions:
# Fusionner des commits (squash)
# Changer 'pick' en 's' ou 'squash' pour les commits à fusionner
# Réécrire un message de commit
# Changer 'pick' en 'r' ou 'reword'
# Diviser un commit
# Changer 'pick' en 'e' ou 'edit'
# Après que git s'arrête :
git reset HEAD^ # Défaire le commit en gardant les changements
git add -p # Stager les changements partiellement
git commit -m "Partie 1"
git add .
git commit -m "Partie 2"
git rebase --continue # Continuer le rebase
Documented commits
Ensuring that changes in our commits are atomic and consistent is not enough — we also need to document them properly.
Convention for a good commit message
Git has a convention for the structure of a well-formed commit message:
[Résumé court (50 caractères maximum)]
[Description plus longue optionnelle. Utilisez-la pour expliquer :
- Le raisonnement derrière un refactoring
- Le problème qu'un correctif résout
- Des instructions sur l'utilisation d'une nouvelle fonctionnalité
Limitez les lignes à 72 caractères pour la lisibilité sur une console
standard de 80 caractères.]
Rules:
- First line: short summary, maximum 50 characters
- Blank line between summary and body
- Optional body: more detailed description, lines of maximum 72 characters
Example:
Renommer calculateTotal() en computeTotal()
La fonction calculateTotal() portait un nom ambigu qui ne reflétait pas
clairement son intention. Le nouveau nom computeTotal() est plus précis
et cohérent avec la nomenclature utilisée dans le reste du projet.
Toutes les références à cette fonction ont été mises à jour dans les
fichiers suivants :
- src/billing.js
- src/invoice.js
- tests/billing.test.js
Use a commit-msg hook to commit messages
To encourage descriptive and well-formed commit messages, we can create a small reminder every time someone is about to make a commit. This callback takes the form of a shell script that runs every time a commit is created in the local repository — a commit-msg hook:
# Créer le répertoire hooks si nécessaire
mkdir -p .git/hooks
# Créer un script commit-msg
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash
# Lire le message de commit
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# Vérifier la longueur de la première ligne (max 50 caractères)
FIRST_LINE=$(echo "$COMMIT_MSG" | head -n1)
if [ ${#FIRST_LINE} -gt 50 ]; then
echo "ERREUR: La première ligne du message de commit dépasse 50 caractères."
echo "Longueur actuelle: ${#FIRST_LINE} caractères."
exit 1
fi
# Vérifier que le message n'est pas vide
if [ -z "$FIRST_LINE" ]; then
echo "ERREUR: Le message de commit ne peut pas être vide."
exit 1
fi
exit 0
EOF
# Rendre le script exécutable
chmod +x .git/hooks/commit-msg
Important: It is generally not recommended to commit hooks to the repository, because the
.gitdirectory is not versioned. A good practice is to store hooks in a versioned directory (eg:./scripts/hooks) and copy them (or create symbolic links) manually or via a setup script.
Private history vs. audience
In Git there is a convention that states that we are never allowed to rewrite public history, only our own private history.
The notion of public versus private history applies to any distributed version control system:
- Everyone works on their own local copy of the repository, building their private history
- Once finished, everyone shares their work through a common instance of the repository, accessible to all
- Once someone’s private history becomes part of a shared repository, it’s no longer just theirs — it becomes public
Linus Torvalds, the original creator of Git, said it well:
“People can (and probably should) rebase their private tree — their own work. That’s a clean-up. But never other people’s code. That’s a destruction of history.”
This means two things:
- If you have not created a commit, it is not your responsibility to modify it.
- If you pushed a commit to a shared repository, other people might have picked it up and built on it — so it’s no longer yours.
Why is this rule necessary?
Every time we change an aspect of a commit, we indirectly change its unique identifier. This ID is generated by calculating the SHA1 of the SHA1 hashes of its combined metadata fields:
- Tree references
- The parent commit
- The author
- The committer
- The commit message
Changing any of these fields will affect the commit ID. And since the parent commit’s ID is part of every subsequent commit, once a commit changes ID, all commits that come after it also change ID — like a domino effect.
If an old commit had been checked out by someone else, once the modified commits are pushed, Git will treat them as completely different commits. This creates a conflict situation that is difficult to resolve.
5. Search History
In this module, we will see how to query the history of our source code to answer any questions we might have about its past or present.
Questions we can answer:
- Which commits are in this branch, but not this other?
- Which commit introduced this line of code?
- Who modified this file in the last few weeks?
The concept of reachability
Before we can start talking about searching a repository’s history, we need to recall the Git object model.
In Git, the history is structured as a Directed Acyclic Graph (DAG). Visually, we can think of it as a series of nodes, where each node always points to the one before it. In the context of Git, each node represents a commit.
Terminology
- Head of a branch: the last commit in its sequence — associated with the name of the branch reference
- Fork points: commits that can have two or more parents
- Merge commits: commits that have two or more parents
Traversing the graph
The only way to traverse this structure is to start from the end (the current commit) and work back to the beginning (the initial commit). This has a direct consequence on how we find commits: a commit is said to be reachable from a reference if we can find it by going up the parent chain from that reference.
The “double-dot” notation (..)
Used with git log to see commits accessible from one branch but not from another:
# Commits dans feature mais pas dans main
git log main..feature
# Commits dans main mais pas dans feature
git log feature..main
The “triple-dot” notation (…)
Used to see commits accessible from either branch, but not both:
# Commits dans feature OU dans main, mais pas dans les deux
git log main...feature
The show-branch command
# Afficher les commits récents dans plusieurs branches
git show-branch main feature bugfix
# Afficher uniquement les commits "topic" (non fusionnés dans la première branche)
git show-branch --topic main feature bugfix
When did this merger take place?
When working with branches, one of the things we want to check regularly is which branches have been merged and which have not.
Merged branches
# Branches fusionnées dans la branche actuelle
git branch --merged
# Branches fusionnées dans une branche spécifique
git branch --merged main
Unmerged branches
# Branches non fusionnées dans la branche actuelle
git branch --no-merged
# Branches non fusionnées dans une branche spécifique
git branch --no-merged main
Find missing commits
To find commits that have been merged into a particular branch:
# Avec git log et la notation double-dot
git log feature..main
# Avec show-branch et l'option --topic
git show-branch --topic main feature
Find when a branch was merged
To find out when the feature branch was merged into main — that is, get the list of Merge commits:
# Lister les merge commits entre feature et main
git log --merges feature..main
# Avec --ancestry-path pour le merge le plus récent
git log --merges --ancestry-path feature..main
Commits vs. Patches
So far we have only tracked entire commits. The commands we used only look at the commit ID to determine whether it is reachable or not — they do not take into account the changes that a commit introduces.
This can sometimes be a problem because we don’t always merge entire branches. Instead, we pick and choose individual commits to apply on a branch, for example, using the cherry-pick command.
Equivalent patch commits
In Git notation, patch-equivalent commits are marked with a prime (e.g. F’). F’ is the commit equivalent to commit F in terms of patch, but has a different commit ID.
The --cherry-mark option
# Trouver les commits équivalents entre branches
git log --cherry-mark main...feature
# Avec l'alias lg (log --oneline)
git lg --cherry-mark main...feature
Interpretation of markers:
=— patch-equivalent commits (present on both sides)<— commits present only on the left (feature side here)>— commits present only on the right (main side here)
Additional options
# Ne voir que les commits d'un côté
git log --cherry-mark --left-only main...feature
git log --cherry-mark --right-only main...feature
# Utiliser --cherry-pick pour exclure les commits équivalents
git log --cherry-pick main...feature
When was this code changed?
The next step is to track changes through commits.
Find commits that modify a file
# Tous les commits qui modifient un fichier spécifique
git log --follow calculator.c
# Avec les changements détaillés
git log --follow --patch calculator.c
The --follow option is important because it tracks file renames.
Search for a character string (-S option)
The -S option (called the “pickaxe”) finds commits that add or remove a specific string:
# Trouver tous les commits qui ajoutent ou suppriment "calculator"
git log -S "calculator"
# Avec une expression régulière
git log -S "calc.*" --pickaxe-regex
Important: The
-Soption only shows commits that add or remove lines — not those that modify them.
Search with regular expressions (option -G)
The -G option is more flexible: it searches for commits whose changes match a regular expression, including line changes:
# Trouver les commits où "subtract" est ajouté, modifié ou supprimé
git log -G "subtract"
Difference between -S and -G:
-S: only show commits that add or remove a match-G: also shows commits that modify a corresponding line
Search by function (-L option)
Git can parse the contents of text files to produce language-aware diffs. The -L option allows you to search by function name:
# Trouver tous les commits qui modifient la fonction subtract
git log -L :subtract:calculator.c
# Alternative avec une expression régulière
git log -L '/^subtract/',/^}/:calculator.c
git blame
To find out which line was modified in which commit and by whom:
# Voir l'attribution ligne par ligne d'un fichier
git blame calculator.c
# Avec un contexte autour d'une ligne spécifique
git blame -L 10,20 calculator.c
# Suivre les mouvements de code entre fichiers
git blame -C calculator.c
Who made this change?
Sometimes knowing which commits modify a certain file is not enough — we need to know who made these changes in order to gather more information about their context.
Filter by author
# Trouver les commits d'un auteur spécifique
git log --author="Enrico"
# Avec l'alias lg
git lg --author="Enrico"
Author vs. Committer
In Git, there is a difference between who wrote a patch (the author) and who committed it to a repository.
# Voir les métadonnées d'un commit
git show --pretty=fuller HEAD
Typical output:
commit abc123...
Author: Contributor Name <contributor@email.com>
AuthorDate: Mon Jan 1 10:00:00 2024 +0100
Commit: Maintainer Name <maintainer@email.com>
CommitDate: Mon Jan 1 14:00:00 2024 +0100
Résumé du commit
In projects like the Linux kernel, it’s common for contributors to submit a patch, which is then reviewed by someone from the maintenance team — who then decides whether the patch should be committed. By recording who wrote the change and who actually committed it in separate fields, Git allows crediting both.
Filter by committer
# Filtrer par committeur
git log --committer="Maintainer"
Filter by time period
# Commits d'un auteur dans la dernière semaine
git log --author="Enrico" --since="1 week ago"
# Autres formats de date
git log --since="2024-01-01" --until="2024-12-31"
git log --since="yesterday"
git log --since="2 weeks ago"
git log --since="3 months ago"
Note: Linus Torvalds, who originally wrote the date parser, called the implementation
approximatein the source code. You can find it in thedate.cfile in the Git repository.
Filter commits that affect a file
# Commits d'un auteur spécifique qui touchent un fichier spécifique
git log --author="Enrico" -- calculator.c
6. Merge correctly
The power of the Git branching model
Branching and merging in Git is radically different from what existed in traditional version control systems. Tools like CVS and Subversion taught us that branching is slow and takes up a lot of disk space — so the natural conclusion was to avoid branching at all costs until it became absolutely necessary.
Git completely overturns this rule by making branching a quick and inexpensive operation.
Connection in traditional systems
In traditional version control systems, branching means creating an exact copy of the entire working tree in a new directory, down to each file. In some systems the directory name becomes the branch name, while others record the directory path and associate it with a name somewhere in their database.
Branching into Git
In Git, creating a branch literally means writing a value to a text file — this value is the SHA1 of the commit which represents the top of the branch (the branch head). The file name itself becomes the branch name. That’s all.
- No files are copied
- No database is updated
- A branch in Git is nothing more than a commit ID stored in a 41 byte text file
Proof:
# Voir le contenu d'un fichier de branche
cat .git/refs/heads/main
# Affiche : abc123def456...
# Créer une branche
git branch feature
# Crée simplement : .git/refs/heads/feature avec le même hash
The different types of branches
Making branching essentially free is one of Git’s greatest achievements. This feature opens up a whole range of workflows that are impossible or very impractical in other version control systems.
Regardless of the version control system, each branch is one of two kinds:
Long-running branches
A long-running branch is a broad-scope branch that exists for a long period of time — from a few weeks to the entire life of the project. They are usually shared within a group of people or the entire team.
Examples:
- The branch where the next major version of the software is working
- The branch that contains bug fixes for a previously released version
- The
mainormasterbranch where all other branches branch off and are merged
All projects must have at least one long-running branch: the main branch.
Topic branches (themes)
A topic branch is an ephemeral, disposable branch that focuses on a very specific task — hence the name “topic”. It is typically narrower in reach than a long-running arm.
Features:
- Created from long-running branches to accomplish a specific goal (implement a feature, fix a bug)
- If they produce useful results, they can be merged into the long-running branch
- Once they are no longer needed, they disappear
Workflow example:
# Branche long-running
git branch vNext
# Branche topic pour une fonctionnalité
git checkout -b feature/add-subtraction vNext
# Travailler sur la fonctionnalité...
git commit -m "Ajouter la fonction de soustraction"
# Fusionner dans vNext quand prêt
git checkout vNext
git merge feature/add-subtraction
# Supprimer la branche topic
git branch -d feature/add-subtraction
The different ways to merge
A branch is created the same way, regardless of its type. What changes is the way it is merged.
Fast-forward merge
Consider this scenario: there are two commits, D and E, reachable from the feature branch but not from main. The important thing to note is that the main branch points to a commit that is an ancestor of the commit referenced by feature.
main: A---B
\
feature: D---E
If we merge feature into main, Git notices that main is already reachable from feature and just moves the reference forward so that it points to the same commit as feature. This is called a fast-forward merge — it does not create a Merge commit.
git checkout main
git merge feature
# Fast-forward, main avance vers E
Result:
main (= feature): A---B---D---E
True merge
In this different scenario, the history line of main diverged from that of feature with the creation of commit C:
main: A---B---C
\
feature: D---E
This time, if we merge feature into main, Git cannot fast-forward because C is not reachable from feature. Instead, Git does a true merge: it applies the changes contained in the snapshots of D and E on top of C, then creates a Merge commit M to link the two history lines.
git checkout main
git merge feature
# Crée un commit de fusion M
Result:
main: A---B---C---M
\ /
feature: D---E
Prevent fast-forward
# Forcer la création d'un Merge commit même si fast-forward est possible
git merge --no-ff feature
This is useful for maintaining branch history in history.
Rebase before merging
If you want to do a fast-forward merge even with a diverged history, you can first rebase the topic branch:
# Se positionner sur la branche feature
git checkout feature
# Rebaser sur main (changer la base de feature vers le dernier commit de main)
git rebase main
As the name implies, rebase allows us to change the base of our commits to another commit. In the example above, D and E are moved to be descendants of the last commit of main (C), which then allows for a clean fast-forward merge.
Result after rebase:
main: A---B---C
\
feature: D'---E'
Then after fast-forward:
main: A---B---C---D'---E'
Cherry-pick
To apply a specific commit from one branch to another:
# Appliquer le commit abc123 sur la branche actuelle
git cherry-pick abc123
# Cherry-pick multiple
git cherry-pick abc123 def456
Resolve conflicts
Every time we merge a commit — during a merge, rebase, or cherry-pick — Git will combine the changes. If a line in a file has been added, deleted, or modified on only one side of the merge, Git will include it in the resulting file without questions. However, if both sides edit the same line, Git can’t decide which to include — it declares a merge conflict and shuts down, waiting for us to resolve the dispute.
Trigger conflict
git merge feature
# Auto-merging calculator.c
# CONFLICT (content): Merge conflict in calculator.c
# Automatic merge failed; fix conflicts and then commit the result.
Check status
git status
# both modified: calculator.c
Abort merge
git merge --abort
File conflict notation
Git uses the same notation as the merge program included in the RCS suite:
<<<<<<< HEAD (Ours)
int result = a + b;
=======
int result = add(a, b);
>>>>>>> feature (Theirs)
- The section above the equal signs (
=======) contains the line as it appears in the branch we are merging to (Ours, referenced by HEAD) - The section below contains the line of the commit being merged (Theirs)
Conflict Resolution Tools
# Configurer un outil de merge
git config --global merge.tool vimdiff
# ou
git config --global merge.tool vscode
# Lancer l'outil de merge
git mergetool
# Voir les 3 versions (base, ours, theirs) avec git diff
git diff --diff-filter=U
See all 3 versions
# Version "ours" (HEAD)
git checkout --ours calculator.c
# Version "theirs" (branche fusionnée)
git checkout --theirs calculator.c
# Version de l'ancêtre commun
git show :1:calculator.c # base
git show :2:calculator.c # ours
git show :3:calculator.c # theirs
Complete merge
After resolving conflicts:
git add calculator.c
git commit
# Git propose un message de commit de fusion automatiquement
Bear vs. Theirs
In a merge conflict, each side is represented as either Ours or Theirs. Although in most version control systems it’s pretty easy to distinguish the two, there is a special case in Git where things aren’t what you’d expect.
During a classic merge
- Ours = the version of the file in the branch to which we are merging (the branch currently checked out)
- Theirs = the version of this same file in the branch which is merged
This makes sense: in Git, you merge someone else’s branch (Theirs) into the one you currently have checked out (Ours).
During a rebase
Warning: During a rebase, Ours and Theirs are inverted compared to a classic merge!
A rebase is a form of merge where each new commit to the branch you are rebasing is applied one by one to the branch you are rebasing to. If one of these commits contains a conflicting change, the operation stops.
In this situation:
- Ours = the branch on which you are rebasing (ex:
main) - Theirs = the branch that you extracted and rebased (ex: your
featurebranch)
This means that in a typical rebase of your own topic (feature) branch to a long-running (main) branch:
- Ours =
main(others’ changes) - Theirs = your own
featurebranch
This is exactly the opposite of a classic merge.
Understanding this behavior is crucial to correctly resolve conflicts during a rebase.
Reuse saved resolutions (rerere)
Git can even help us resolve the same conflict multiple times, thanks to a little-known feature called rerere (Reuse Recorded Resolution).
Why would we need it?
Consider this workflow:
- We have a private topic branch named
featurethat we have been working on for a while - To ensure that our changes are still compatible with the long-running branch, we do a test merge of
featureintomain - This merge results in a conflict that we resolve
- Later, we want to merge cleanly, so we do a rebase which reproduces the same conflict
Without rerere we would have to resolve the same conflict twice.
Enable rerere
git config --global rerere.enabled true
Workflow with rerere
# 1. Activer rerere dans la configuration
git config rerere.enabled true
# 2. Essayer de fusionner (conflit prévisible)
git merge feature
# CONFLICT...
# 3. rerere enregistre l'état du conflit
# "Recorded preimage for 'calculator.c'"
# 4. Résoudre le conflit manuellement
# (éditer le fichier)
# 5. Stager le fichier résolu
git add calculator.c
# 6. rerere enregistre la résolution
git commit
# "Recorded resolution for 'calculator.c'"
# 7. Annuler la fusion de test (on voulait juste tester)
git reset --hard HEAD^
# 8. Rebaser feature sur main (même conflit se produit)
git rebase main
# CONFLICT...
# "Resolved 'calculator.c' using previous resolution."
# 9. rerere applique automatiquement la résolution précédente !
git add calculator.c
git rebase --continue
Useful rerere commands:
# Voir les résolutions enregistrées
git rerere status
# Afficher les différences des résolutions
git rerere diff
# Supprimer une résolution enregistrée
git rerere forget <fichier>
7. Fix errors
In this module, we will discover the forgiving nature of Git by learning how to rewrite our repository history in order to correct an error or reverse a previous decision.
Amend commits
We all make mistakes. Sometimes we wouldn’t even call it a mistake — we just change our mind about a choice previously made. This happens all the time, especially in programming.
Fortunately, Git is different from traditional version control systems which were rather unforgiving when it came to changing history. Once something was committed to source control, it became final. Git is happy to let us change our history — as long as we haven’t shared it with anyone else.
Amend last commit
Imagine we’ve just made a commit and suddenly realize we forgot to include a file:
# Oups, oublié un fichier !
git add missing-file.js
# Amender le commit précédent
git commit --amend
# Amender sans changer le message de commit
git commit --amend --no-edit
The --amend option causes the contents of the index to become part of the same commit referenced by HEAD. When doing this, the default editor opens with the message of this commit, allowing further clarification if necessary.
Note: Technically,
git commit --amenddoes not modify the existing commit — it creates a new commit with a new ID and replaces the old one. The old commit remains in the repository until the garbage collector deletes it. This is why you should never amend a commit that has already been pushed.
Amend an older commit
To modify an older commit, we use the interactive rebase:
# Rebase interactif pour les 3 derniers commits
git rebase -i HEAD~3
In the editor, change pick to edit for the commit to edit:
edit abc1234 Commit à modifier
pick def5678 Commit suivant
pick ghi9012 Dernier commit
Git will stop at the commit marked edit. Make your changes, then:
# Après avoir fait les modifications
git add .
git commit --amend --no-edit
# Continuer le rebase
git rebase --continue
Split a commit
If a commit contains too many changes and needs to be split:
git rebase -i HEAD~3
# Marquer le commit avec 'edit'
# Défaire le commit en gardant les changements dans le working directory
git reset HEAD^
# Stager et commiter les changements séparément
git add partie1.js
git commit -m "Partie 1: Refactoring"
git add partie2.js
git commit -m "Partie 2: Nouvelle fonctionnalité"
git rebase --continue
Merge multiple commits (squash)
git rebase -i HEAD~4
# Marquer les commits à fusionner avec 'squash' ou 's'
pick abc1234 Premier commit
squash def5678 Deuxième commit (sera fusionné avec le premier)
squash ghi9012 Troisième commit (sera fusionné avec le premier)
pick jkl3456 Quatrième commit (reste séparé)
The Git Undo command
Sometimes when we rewrite our commits, we end up with a history that no longer looks at all like what we wanted. When this happens, we wish there was a way to undo our actions — like we can do in any editing software.
There is, in fact, a way to undo our actions in Git.
The Reflog
Every time a branch reference moves — that is, it points to a different commit than the one it previously pointed to — Git records its previous position in a kind of log called the Reflog.
In each repository, there is a Reflog for each branch, as well as one for the HEAD reference.
# Voir le Reflog de la branche main
git reflog main
# Voir le Reflog de HEAD
git reflog
# ou simplement
git reflog show
Typical output:
abc1234 HEAD@{0}: rebase -i (finish): returning to refs/heads/main
def5678 HEAD@{1}: rebase -i (squash): Fusion de commits A et B
ghi9012 HEAD@{2}: rebase -i (pick): Commit A
jkl3456 HEAD@{3}: checkout: moving from feature to main
Reflog characteristics:
- Entries are in reverse chronological order (newest on top)
- Each entry has an index that can be used to reference the commit
Syntax for referencing Reflog entries
# Voir le commit vers lequel HEAD pointait 2 positions en arrière
git show HEAD@{2}
# Voir le commit vers lequel main pointait avant le dernier déplacement
git show main@{1}
Implement an “undo” with Reflog
The magic happens when you combine Reflog with the git reset command:
# Annuler la dernière opération (retourner à la position précédente de HEAD)
git reset --hard HEAD@{1}
This looks like the classic “Undo” button! In fact, we can create an alias for that:
# Créer un alias "undo" pour Git
git config --global alias.undo "reset --hard HEAD@{1}"
# Utilisation
git undo
Warning:
git reset --hardoverwrites changes in the working directory. Use it with caution.
Difference between git reset and git revert
git reset: move branch reference to an earlier commit — rewrite history (private only)git revert: creates a new commit that reverts changes from a previous commit — does not rewrite history (safe for public history)
# Annuler le dernier commit avec revert (crée un nouveau commit)
git revert HEAD
# Annuler un commit spécifique
git revert abc1234
# Annuler sans créer immédiatement un commit
git revert --no-commit abc1234
Recover lost commits
Git, at its core, is designed to work as a file system, and as such, it places great importance on the integrity of our data. So when we move, edit or delete commits when rewriting history, nothing is actually lost.
Even if there seems to be no way to retrieve a commit, there is always one last reference: the HEAD Reflog, because it records all commits that have been referenced by HEAD at one time or another.
Shelf life in Reflog
Warning: Entries in the Reflog will not remain forever. Git will delete entries older than a certain number of days as part of a garbage collection cycle:
- 90 days for commits still achievable
- 30 days for unreachable commits
# Configurer la durée de conservation du Reflog
git config gc.reflogExpire "120 days"
git config gc.reflogExpireUnreachable "60 days"
What this means for our daily work: we can rewrite our history as much as we want without having to worry about losing commits — they will still be in the repository for between 30 and 90 days before finally being deleted.
Retrieve a specific commit
Suppose our history was initially:
A---B---C---D---E (main)
But accidentally during an interactive rebase we deleted commit C, so the history now looks like:
A---B---D'---E' (main)
# Chercher le commit perdu dans le Reflog par message
git log --grep="message du commit C" -g
# Alternative : chercher dans le Reflog
git reflog | grep "message du commit C"
# Une fois le hash trouvé (ex: abc123)
# Option 1 : Créer une nouvelle branche pointant vers le commit
git branch recovery abc123
# Option 2 : Cherry-pick le commit sur la branche actuelle
git cherry-pick abc123
# Option 3 : Reset vers ce commit (si c'est ce que vous voulez)
git reset --hard abc123
Find “orphan” commits with git fsck
# Trouver tous les commits inatteignables dans le dépôt
git fsck --lost-found
# Voir les commits "dangling" (pendants)
git fsck | grep "dangling commit"
# Voir le contenu d'un commit dangling
git show <hash-du-commit-dangling>
Debug with Bisect
Incredibly, Git can even help us track down a problem in our code base using the git bisect command.
The problem
Imagine that you have just retrieved the latest commit from a shared repository and decide to run the build script to verify that everything is okay. Problem: The code does not compile.
The first thing we want to know is: when did this happen? Or more precisely: which commit broke our code?
- If we know exactly where the problem is, we could respond fairly quickly using
git blame - If we can’t determine where the problem is, we would have to manually review a large number of commits — tedious in the extreme
The git bisect command
git bisect, as the name suggests, unbinds our code by binary searching through its commit history.
Start a bisect session
# Démarrer la session bisect
git bisect start
# Marquer le commit actuel comme mauvais (le problème existe ici)
git bisect bad
# Marquer le dernier bon commit connu
git bisect good A # ou un hash de commit, ou HEAD~10
Git now has enough information to start bisecting. It starts by moving HEAD to the commit in the middle of the range, in this case C.
Iterative process
# Tester le commit actuel (Git s'est placé au milieu)
make # ou npm test, ou ./run_tests.sh, etc.
# Si le test réussit (commit est bon)
git bisect good
# Si le test échoue (commit est mauvais)
git bisect bad
# Git continue à bisectionner jusqu'à trouver le premier commit mauvais
# Répéter jusqu'à ce que Git annonce :
# "abc123 is the first bad commit"
Automate with bisect run
If you have an automated script that returns 0 for “good” and non-zero for “bad”:
# Démarrer bisect
git bisect start
git bisect bad HEAD
git bisect good HEAD~20
# Automatiser complètement
git bisect run ./run_tests.sh
# ou avec une commande simple
git bisect run make test
Git will run the script on each commit and automatically find the first bad commit.
End bisect session
Once the problematic commit is found:
# Retourner à HEAD et terminer la session
git bisect reset
# ou retourner à une branche spécifique
git bisect reset main
Full example
Historique : A---B---C---D---E (HEAD - mauvais)
A : bon, E : mauvais
git bisect start
git bisect bad # E est mauvais
git bisect good A # A était bon
# Git place HEAD sur C (milieu)
# Tester...
git bisect bad # C est mauvais aussi
# Git place HEAD sur B (milieu de A..C)
# Tester...
git bisect good # B est bon
# Git identifie : "C is the first bad commit"
git bisect reset
Efficiency: With binary search over N commits, git bisect requires only log2(N) steps. For 1000 commits, only 10 steps are needed!
Show tested commits
# Voir le log de la session bisect
git bisect log
# Rejouer une session bisect sauvegardée
git bisect log > bisect-session.txt
git bisect replay bisect-session.txt
8. Course Summary
In this Git Tips and Tricks training, we explored Git’s design philosophy and learned how to leverage its advanced features to improve our daily workflow.
Key points retained
Module 2 — The command line
- CLI is more powerful and flexible than any GUI for Git
- posh-git for Windows, Oh My Zsh with Zsh for Linux/macOS
- Git fundamentals: commits, snapshots, references (tags, branches, HEAD)
Module 3 — Command line experience
- aliases allow you to create shortcuts for all kinds of commands
- git log with custom formats and
--graphfor nice visualization - Delta as pager for more readable diffs
git showto inspect individual commits
Module 4 — Own history
- Good commits are ACID: Atomic, Consistent, Incremental, Documented
- index (staging area) allows atomic commits
- The stash allows testing the contents of the index separately
- Interactive rebase allows cleaning local history
- The commit-msg hook encourages good commit messages
- Never rewrite public history
Module 5 — History Search
- Reachability: how Git traverses the commits graph
..and...notation to compare branchesgit log -Sto find commits that add/remove a stringgit log -Gfor line changesgit log -Lto track changes in a functiongit blameto identify the author of each line- Filtering by author, committer and date
Module 6 — Merge Correctly
- A branch in Git = a 41 byte text file
- Fast-forward merge vs. True merge
- Rebase to maintain linear history
- Ours/Theirs notation is inverted during a rebase vs. a merger
- rerere to reuse saved conflict resolutions
Module 7 — Correcting Errors
git commit --amendto modify the last commit- The interactive rebase to modify, split or merge older commits
- The Reflog: the log of all reference movements
git reset --hard HEAD@{1}as implementation of an “undo”- Lost commits are recoverable for 30-90 days
git bisectto track the commit that introduced a bug
9. Command Quick Reference
Useful aliases
# Status court
git config --global alias.st "status --short"
# Log graphique amélioré
git config --global alias.lg "log --pretty=format:'%C(yellow)%h%Creset %C(blue)%d%Creset %s %C(green)%cr%Creset' --graph"
# Supprimer les branches fusionnées
git config --global alias.dm '!git branch --merged | grep -v "^\*\|main\|master" | xargs git branch -d'
# Undo (annuler la dernière opération)
git config --global alias.undo "reset --hard HEAD@{1}"
Staging and commits
git add -p # Staging partiel (hunk par hunk)
git diff --staged # Voir ce qui est stagé
git diff --check # Vérifier les espaces blancs
git stash --keep-index # Stasher les changements non stagés
git commit --amend # Amender le dernier commit
git rebase -i HEAD~N # Rebase interactif sur N commits
History search
git log --follow -- fichier.c # Suivre un fichier (avec renommages)
git log -S "chaine" # Commits qui ajoutent/suppriment une chaîne
git log -G "regex" # Commits qui modifient des lignes correspondantes
git log -L :fonction:fichier.c # Commits qui modifient une fonction
git log --author="Nom" # Filtrer par auteur
git log --since="1 week ago" # Filtrer par date
git blame fichier.c # Attribution ligne par ligne
Branches and merges
git branch --merged # Branches fusionnées
git branch --no-merged # Branches non fusionnées
git log main..feature # Commits dans feature mais pas dans main
git log --cherry-mark main...feature # Comparer les patches entre branches
git merge --no-ff feature # Fusion sans fast-forward
git rebase main # Rebaser sur main
git config rerere.enabled true # Activer rerere
Recovery
git reflog # Journal des déplacements de HEAD
git show HEAD@{2} # Voir un état précédent de HEAD
git reset --hard HEAD@{1} # Annuler la dernière opération
git cherry-pick abc123 # Appliquer un commit spécifique
git fsck --lost-found # Trouver des commits orphelins
Bisect
git bisect start # Démarrer une session bisect
git bisect bad # Marquer le commit actuel comme mauvais
git bisect good HEAD~10 # Marquer un bon commit connu
git bisect run ./test.sh # Automatiser le bisect
git bisect reset # Terminer la session bisect
Search Terms
git · ci/cd · devops · commits · command · commit · merge · history · alias · bisect · branches · search · show · line · filter · find · option · reflog · aliases · amend · conflict · incremental · notation · rebase