Git
Apparence
Links
OhMyZsh Aliases
Alias | Command |
---|---|
g | git |
ga | git add |
gaa | git add --all |
gc | git commit --verbose |
gc! | git commit --verbose --amend |
gcmsg | git commit --message |
gca | git commit --verbose --all |
gca! | git commit --verbose --all --amend |
gcan! | git commit --verbose --all --no-edit --amend |
gcam | git commit --all --message |
gsw | git switch |
gswc | git switch -c |
gswm | git switch $(git_main_branch) |
gcp | git cherry-pick |
gf | git fetch |
gfa | git fetch --all --prune |
ggfl | git push --force-with-lease origin $(current_branch) |
ggl | git pull origin $(current_branch) |
ggp | git push origin $(current_branch) |
grs | git restore |
grst | git restore --staged |
grh | git reset |
grhh | git reset --hard |
gpristine | git reset --hard && git clean -dffx |
gst | git status |
gsta | git stash push |
gstu | git stash --include-untracked |
gstp | git stash pop |
init
# execute the command from the root of the future repo
git init
|
clone
# create a folder containing a copy of the remote repo
git clone git://url/projet.git [destination]
# if destination is not set, git will extract the destination name from the url (here: projet)
# get only the latest version of a repo
git clone --depth 1 --recurse-submodules --shallow-submodules git://url/projet.git
# --branch <branch_name> get another branch or tag
# --filter=blob:none get a blobless clone: without files content
# --filter=tree:none get a treeless clone: without files content and folders
|
add
Move files from the Working Directory to the Index.
# add file.ext from the Working Copy to the Index
git add file.ext
# add all the files and folders from the Working Copy to the Index
git add .
# git add -u → add only the modified and deleted, but not the new and untracked files
# git add -n → dry-run
# remove file.ext from the Index and keep it in the Working Directory
git rm --cached file.ext
# remove all the files and folders from the Index and keep them in the Working Directory
git rm --cached -r .
|
patch
Select interactively blocks of modifications to index them.
git add -p file.ext |
commit
Move changes from the Index into a new commit to the Head.
# create a new commit and move in it the staged files (Index)
git commit
# -m 'commit message'
# move from the Working Directory to the Index all the modified and new files
# then create a new commit and move in it the staged files (Index)
git commit -a
|
status
# display paths that have been modified
git status
# -v show the textual changes that are staged to be committed (like git diff --cached)
# -vv also show the changes in the working tree (like git diff)
|
diff
# display changes in the working tree not yet staged for the next commit
git diff
# display changes between the index and your last commit
git diff --cached
# compare file.ext between 2 branches
git diff master MaBranche -- file.ext
|
restore
Undo changes in the Working Tree and/or the Index (unstage).
# undo the unstaged changes made in file.txt
git restore file.txt
# undo all the unstaged changes
git restore .
# unstage changes made in file.txt (same as git reset --mixed file.txt)
git restore file.txt --staged
# unstage then undo the changes made in file.txt (same as git reset --hard file.txt)
git restore file.txt --staged --worktree
|
reset
# unstage all
git reset
# default values: git reset --mixed HEAD
# unstage all then undo all changes made in the working directory
git reset --hard
|
# merge the changes from HEAD to HEAD~x with the current index
# in cases of conflict, current index overwrites changes from commits
# working directory remains unchanged
# delete all the commits from HEAD to HEAD~x (not included)
git reset --soft HEAD~x
# merge the changes from HEAD to HEAD~x with the current index
# then move and merge the index with the working directory
# in cases of conflict working directory overwrites current index which overwrites changes from commits
# delete all the commits from HEAD to HEAD~x (not included)
git reset HEAD~x
# delete all the commits from HEAD to HEAD~x (not included)
# unstage all then undo all changes made in the working directory
git reset --hard HEAD~x
|
amend
Update the last commit.
# add the modification to the index
# then update the last commit with the changes from the index
git commit --amend
# --author "New Author Name <email@address.com>" update the author
# -m "New comment" update the comment
|
Modify a previous commit
# rebase the branch on the parent of the commit to modify
git rebase -i [HEAD~x|commit_id]
# last commit : HEAD , before last commit : HEAD~1 , parent of the before last commit : HEAD~2
# first commit: --root
# use 'git log' to get the HEAD~x or the commit id
# you can edit (e), reword (r), drop (d), squash (s)
# update the files and add them to the index
git add .
# then update the current commit
git commit --amend
# finish the rebase
git rebase --continue
|
![]() |
All the commits between the one which will be modified and HEAD will be re-written. |
stash
# move the changes of the WD and the Index to a temporary branch
git stash
# --include-untracked / -u stash untracked files too
# --keep-index / -k move only the changes of the WD
# --staged / -S move only the changes of the Index
# move back the changes to the WD and the Index
# delete the temporaray branch
git stash pop
# list the stashes
git stash list
# drop a specific stash
git stash drop stash@{x}
# drop all the stashes
git stash clear
|
cherry-pick
git checkout my-branch
# apply a specific commit to the current branch
git cherry-pick [commit-id]
|
Undo the modifications
# remove the WD modifications of file.ext only
git checkout -- file.ext
# remove the WD and Index modifications of the whole repository
git reset --hard
# delete the unversioned files
git clean -dfx
# -d recurse into folders
# -f needed if clean.requireForce is set to true
# -x don’t follow the ignore rules (.gitignore, $GIT_DIR/info/exclude)
# -n dry-run
|
Move the HEAD
# move the HEAD to a specific commit (detached head state)
git checkout [commit-id]
# move back to the last commit
git checkout [branch-name]
|
Étiquetage (Tags)
![]() |
Par défaut la commande git push n'envoie pas les étiquettes vers les serveurs distants. Pour ce faire : git push --tags |
Créez des étiquettes
# Étiquette la dernière validation
git tag v2.0
# Étiquette la dernière validation dont la somme de controle commence par 9fceb02
git tag v1.2 9fceb02
# Supprimez le tag v1.2
git tag -d v1.2
# Supprimez le tag v1.2 sur la branche distante
git push --delete origin v1.2
|
Listez vos étiquettes
# Listez les étiquettes existantes
git tag
# Recherchez les étiquettes correspondant à un motif particulier
git tag -l 'v1.*'
# Affichez le commit correspondant au tag v1.0.0
git show v1.0.0
|
branch
# create a new branch from the last commit of the current branch
git branch [NewBranch]
# create a new branch from another branch or a specific commit or a tag
git branch [NewBranch] [BranchName|CommitId|HEAD~x|Tag]
# switch to another branch
git switch [BranchName]
# unable to switch if you have local changes
# -c create the branch if needed
# -m merge local changes to the destination branch
# delete a fully merged branch
git branch -d [BranchName]
# -D if the branch is not fully merged
# rename the current branch
git branch -m [NewBranchName]
|
Merge
# merge branch1 into main:
# 1 - switch to main
git switch main
# 2 - merge branch1 into the current branch: main
git merge branch1
# in case of conflicts starts the merge tool
git mergetool
|
Undo a merge as last commit
git reset --merge HEAD~1 |
Rebase
# rebase branch1 onto main
git rebase main branch1
|
Undo a rebase
# get the head commit before the rebase started
git reflog
# reset to head commit just before the rebase started
git reset --hard HEAD@{X}
|
Rebase vs Merge
- Merge: create a new commit in the destination branch with the changes from the source branch
- Rebase: rewrite the divergent commits on top of the source branch
![]() |
Don't rebase commits already pushed on a shared remote repository, because it will rewrite the history and may trouble those who already worked on that version of the branch. |
General rules:
- When pulling changes from origin/develop onto your local develop use rebase.
You are the only one to use this local branch so you can rewrite the history without trouble. - When finishing a feature branch merge the changes back to develop.
It will squash all the commits of the branch into one commit into the shared branch.
Dépots distants
Ajoutez des dépôts distants
# listez les dépôts distants
git remote -v
# ajoutez un dépôt distant (nom donné au dépôt: origin)
git remote add origin git://github.com/createur/projet.git
# if the remote branch doesn't exist yet, push the current branch and set the remote as upstream
git push --set-upstream origin main
# origin = <remote repository name>
# main = <local branch name>
# si la brache distante existe déjà, lier origin/master à la branche courante
git branch -u origin/main
# -u origin/main : --set-upstream-to=origin/main
# origin/main = <remote branch name>
# renommez un dépôt distant
git remote rename current_name new_name
# retirez un dépôt distant
git remote rm repo_name
# modifier l'url du dépôt distant
git remote set-url origin https://github.com/createur/projet.git
|
Mise à jour et validation
# récupère les modifications effectués sur le dépôt distant origin (met à jour les branches distantes origin/*)
# ne modifie pas la branche courante ni ne bascule vers une autre branche
git fetch origin
# fusionne la branche distante origin/master dans la branche locale courante
git merge origin/master
# récupérer la branche MaBranche du dépôt distant origin et la nommer localement MaBranche
git branch MaBranche origin/MaBranche
# équivalent avec checkout en plus
git checkout -b MaBranche origin/MaBranche
git checkout --track origin/MaBranche
# fetch + merge : récupère les modifications effectués sur le dépôt distant et les fusionne avec la branche courante
git pull origin master
# Pousser son travail sur un dépôt distant
git push --tags origin master
# --tags permet de pousser ses tags vers le dépôt distant, ce que ne fait pas push par défaut
# Pousser une branche locale nouvellement créée
git push -u origin <Ma_Nouvelle_Branche>
|
Branches des dépôts distants
# listez les branches distantes
git branch -r
# listez toutes les branches
git branch -a
# url d'une branche distante
git config --get remote.origin.url
# supprimez branch-to-delete sur le dépôt distant origin
git push origin --delete branch-to-delete
git push origin :branch-to-delete
|
Ignore future modifications
# only on the local branch
git update-index --assume-unchanged <file>
# list files that are ignored locally
git ls-files -v . | grep ^h
# undo
git update-index --no-assume-unchanged <file>
# on both local and upstream
git update-index --skip-worktree <file>
# list files that are ignored both locally and upstream
git ls-files -v . | grep ^S
|
Noms de branches insensible à la casse
Les noms de branches git ne sont pas sensible à la casse
# checkout d'une branche distante en minuscule vers une branche locale en majuscule
git checkout -b My_New_Branch /origin/my_new_branch
# pull fonctionne, mais lors du push, création d'une nouvelle branche en majuscule
# renommer My_New_Branch en my_new_branch
# comme git est insensible à la casse il faut passer par une branche intermédiaire
git branch -m My_New_Branch tmp_branch
git branch -m tmp_branch my_new_branch
|
Autre solution: forcer git à ignorer la casse
%HomePath%\.gitconfig |
[core]
ignorecase = true
|
# supprimer les branches locales et locale-remote
# mettre à jour les branches distantes
git fetch -p
|
Exportez dans une archive
git archive mon_tag -o mon_archive.zip -9 --prefix=mon_dossier/
# -9 compression max de l'archive, -0 pas de compression
# HEAD peut-être utilisé comme tag
# tar.gz
git archive mon_tag --prefix=mon_dossier/ >mon_archive.tar.gz
|
Blame
# Affiche les lignes 12 à 22 de fichier.ext avec pour chaque ligne son auteur et la révision associée
git blame -L 12,22 fichier.ext
# seulement la ligne 12
git blame -L 12,12 fichier.ext
# avec une interface graphique, ouvre fichier.ext à la ligne 12
git gui blame --line=12 fichier.ext
# blame a deleted file
# git blame works when providing a commit reference that contains the file. Find the most recent one with log
git log -2 --oneline -- deletedFile.cs
# ac173c96f Merged PR 121163: File already deleted
# 37f91c2fa Merged PR 113177: Before deleting file
git blame 37f91c2fa -- deletedFile.cs
git gui blame 37f91c2fa deletedFile.cs
|
bisect
Définit un commit de début et un commit de fin et permet de lancer un test sur chaque commit intermédiaire.
Permet de localiser un commit introduisant un bug.
Installation
sudo pacman -S git tk
# tk pour gitk
# sans tk l'erreur suivante s'affiche: /usr/bin/gitk: line 3: exec: wish: not found
|
~/.bashrc |
# activer l'autocomplétion
source /usr/share/git/completion/git-completion.bash
|
GUI
- Gittyup (linux / windows)
- gitk, installé avec git. Nécessite l'installation du paquet tk. À lancer dans le répertoire à analyser.
- GitFiend (linux)
- GitKraken (la version gratuite ne supporte pas les dépôts privés ni azure)
- giggle (linux)
- Git Extensions (windows)
Git for Windows
choco install git |
- MinGW64
- MinTTY, thèmes: C:\Users\<Moi>\.mintty\themes\*.minttyrc
- Customize your Windows Git shell, MinTTY
.bashrc |
alias g='git'
alias ga='git add'
alias gaa='git add --all'
alias gc='git commit --verbose'
alias gc!='git commit --verbose --amend'
alias gcmsg='git commit --message'
alias gca='git commit --verbose --all'
alias gca!'=git commit --verbose --all --amend'
alias gcan!='git commit --verbose --all --no-edit --amend'
alias gcam='git commit --all --message'
alias gb='git branch'
alias gba='git branch -a'
alias gbdr='git push origin --delete'
alias gsw='git switch'
alias gswc='git switch -c'
alias gswm='git switch $(git_main_branch)'
alias gcp='git cherry-pick'
alias gf='git fetch'
alias gfa='git fetch --all --prune'
alias ggfl='git push --force-with-lease origin $(current_branch)'
alias ggl='git pull origin $(current_branch)'
alias ggp='git push origin $(current_branch)'
alias grs='git restore'
alias grst='git restore --staged'
alias grh='git reset'
alias grhh='git reset --hard'
alias gpristine='git reset --hard && git clean -dffx'
alias gst='git status'
alias gsta='git stash push'
alias gstu'=git stash --include-untracked'
alias gstp='git stash pop'
# Enable the __git_complete function to autocomplete aliases once you press TAB
source '/c/Program Files/Git/mingw64/share/git/completion/git-completion.bash'
__git_complete ga _git_add
__git_complete gc _git_checkout
__git_complete gsw _git_switch
__git_complete gswc _git_switch
__git_complete gm _git_merge
__git_complete gb _git_branch
__git_complete gba _git_branch
__git_complete gbdr _git_branch
__git_complete l _git_log
function git_main_branch() {
def=`git remote show origin | sed -n '/HEAD branch/s/.*: //p'`
echo $def
}
function git_current_branch() {
local ref
ref=$(__git_prompt_git symbolic-ref --quiet HEAD 2> /dev/null)
local ret=$?
if [[ $ret != 0 ]]; then
[[ $ret == 128 ]] && return # no git repo.
ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return
fi
echo ${ref#refs/heads/}
}
function __git_prompt_git() {
GIT_OPTIONAL_LOCKS=0 command git "$@"
}
|
SSH
# Configuring Git to Leverage the Windows SSH-Agent
git config --global core.sshCommand C:/Windows/System32/OpenSSH/ssh.exe
|
Filename too long
git config --system core.longpaths true
|
SSL Certificate problem: unable to get local issuer certificate
Configure Git to use Secure Channel instead of OpenSSL. This means that it will use the Windows certificate storage mechanism.
git config --global http.sslbackend schannel
|
Configuration
Fichiers
- .git/config accès par défaut ou avec l'option --local
- ~/.gitconfig accès avec l'option --global
- /etc/gitconfig accès avec l'option --system
# ouvre le fichier de configuration dans le éditeur de texte
git config --global --edit
git config --system --edit
git config --local --edit # work only from a git repo
# display all the config by file
git config --list --show-origin
|
Commandes
git config --global core.editor "nano -w"
git config --global user.name "Prénom Nom"
git config --global user.email "compte@email.com"
git config --global color.ui true
git config --global merge.tool meld
# autorise git à conserver le mot de passe pendant 15mn (valeur par défaut)
git config --global credential.helper cache
# autorise git à conserver le mot de passe pendant 1h
git config --global credential.helper 'cache --timeout=3600'
# stocke les informations d'identification dans le fichier ~/.git-credentials
git config --global credential.helper store
# LF - CRLF
# for Windows user: convert to LF while commiting and convert to CRLF while checking out
git config --global core.autocrlf true
# for Linux users: convert to LF while checking out in case there are unexpectedly
git config --global core.autocrlf input
# checkout et commit des fichiers tels quels
git config --global core.autocrlf false
# Gnome Keyring
# compilez le credential pour gnome-keyring
cd /usr/share/git/credential/gnome-keyring
sudo make
# configurez git
git config --global credential.helper /usr/share/git/credential/gnome-keyring/git-credential-gnome-keyring
|
~/.gitconfig |
[core]
editor = nano -w
autocrlf = input ; for GNU/Linux OS
[user]
name = Prénom Nom
email = compte@email.com
[color]
ui = true ; get the color in the console
[merge]
tool = meld
tool = kdiff3
[mergetool "kdiff3"]
path = C:/Program Files/KDiff3/kdiff3.exe
trustExitCode = false
[credential]
helper = cache | store
|
Les alias Git
# permet de taper 'git unstage' au lieu de 'git reset HEAD --'
git config --global alias.unstage 'reset HEAD --'
# alias pour visualiser plus facilement le dernier commit
git config --global alias.last 'log -1 HEAD'
# permet de taper 'git ci' au lieu de 'git commit'
git config --global alias.ci commit
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
|
~/.gitconfig |
[alias]
unstage = reset HEAD --
last = log -1 HEAD
ci = commit
co = checkout
br = branch
st = status
|
git diff avec meld
meld
# se placer dans le dossier git
meld .
|
difftool
git difftool -y fichier.ext
# -y: no prompt
|
diff external
git-diff-meld.sh |
#!/bin/bash
meld $2 $5
|
git config --global diff.external /path/to/git-diff-meld.sh |
~/.gitconfig |
[diff]
external = /path/to/git-diff-meld.sh
|
Normalizing Line Endings
.gitattributes |
; at the source of your repo
; normalizes all line endings to LF when committing text files into your repo
; does not modify line endings in your working tree when checking-out
; equivalentb of autocrlf=input
* text=auto
|
# after the creation or a modification of line endings setting in .gitattributes
# apply the change to the repo: updates all tracked files in your repo
git add --renormalize .
# verifying Line Endings
git ls-files --eol
# i/lf: index (repo), LF
# w/crlf: working directory, CRLF
# i/mixed: index, mixed of LF and CRLF
# i/none: index, no line ending
# i/-text: index, binary file
|
Value | checkout | commit | OS |
---|---|---|---|
input | - | LF | GNU/Linux |
true | CRLF | LF | Windows OS |
false | - | - | - |
git-filter-repo
Change the author of all the commits
mailmap |
NewName <new@email.com> <old@email.com>
|
cd MyProject
git filter-repo --mailmap ../mailmap --force
# Git filter-repo deletes the remote address repository to protect from accidental overwrites.
git remote add origin user@server:repo.git
git push --set-upstream origin main --force
|
Serveur Git
# créer un dossier de stockage
cd /srv
mkdir git
chown git:git git
# créer un projet de test
cd /srv/git
git init project.git --bare --shared
# bare: dépôt vide
# shared: dépôt partagé rwxrwsr-x au lieu de rwxr-xr-x
# et le fichier config contient sharedrepository = 1 et denyNonFastforwards = true
chown -R git:git project.git
# ajouter le groupe git aux utilisateurs pour qu'ils puissent pousser leurs modifications
# ajouter le dépôt fraîchement créé à un dépôt local
git remote add origin user@server:/srv/git/projet.git
# envoyer les modifications locales vers le dépôt distant
git push origin master
# récupérer le projet depuis un client avec le protocole ssh
git clone user@server:/srv/git/projet.git
# démarrer le serveur Git. Seulement utile pour le protocole git
systemctl start git-daemon.socket
|
Protocoles
local | le dépôt distant est un autre répertoire dans le système de fichiers par exemple un répertoire partagé via NFS |
git clone /srv/git/projet.git
|
ssh | permet de cloner et de pousser | git clone utilisateur@serveur:/srv/git/projet.git
|
git | daemon écoute sur le port 9418 pas d'authentification, tous le monde peut cloner et pousser |
|
http(s) | permet de cloner mais pas de pousser | git clone http://server/projetgit.git
|
Gitweb
pacman -S perl-cgi fcgiwrap
# démarrer le service fcgiwrap
sc-start fcgiwrap.socket
|
/etc/nginx/nginx.conf |
server {
listen 80;
server_name gitweb.myserver;
location /gitweb.cgi {
include fastcgi_params;
gzip off;
fastcgi_param SCRIPT_FILENAME /usr/share/gitweb/gitweb.cgi;
fastcgi_param GITWEB_CONFIG /etc/gitweb.conf;
fastcgi_pass unix:/run/fcgiwrap.sock;
}
location / {
root /usr/share/gitweb;
index gitweb.cgi;
}
}
|
/etc/gitweb.conf |
# The directories where your projects are. Must not end with a slash.
our $projectroot = "/srv/git";
# Base URLs for links displayed in the web interface.
our @git_base_url_list = qw(git://myserver http://git@myserver);
# enable "blame" view
$feature{'blame'}{'default'} = [1];
# enable syntax highlighting (installer le package highlight)
$feature{'highlight'}{'default'} = [1];
|
Gitolite
- Gitolite on Ubuntu ARM 18.04