Outils pour utilisateurs

Outils du site


prog:git

Table des matières

Dépôts

Cloner et configurer d'un dépôt

git clone https://github.com/bansan85/2lgc.git

Mais surtout, ne pas oublier (l'option –global configure tous les dépôts et pas uniquement le dépôt courant) :

# Définition de l'auteur des commit
git config --global user.name <name>
git config --global user.email <email>
# Toujours signer les commit
git config --global user.signingkey YYYYYYYYY
git config --global commit.gpgsign true
# Ne pas faire de pause lors de l'affichage des logs
git config --global pager.log false
git config --global pager.diff false
git config --global pager.grep false
# lfs
git config --global lfs.locksverify true

Données privées

Si le dépôt demande constamment le mot de passe, il faut soit configurer l'utilisation de clés privées / publiques SSH et utiliser le protocole git@, soit stocker les mots de passe (en clair sur le disque) et utiliser https:// :

git config --global credential.helper store

How to Save Username and Password in Git Archive du 04/09/2022 le 14/10/2022

WSL

  • Chemin d'accès depuis Windows

Il est possible d'accéder aux dépôts git de WSL depuis Windows. Le chemin d'accès est : \\wsl.localhost\Ubuntu-22.04\home\….

  • Autorisation à WSL

git détecte le dossier comme anormal. Il faut autoriser explicitement l'accès à chaque dépôt avec la commande :

git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu-22.04/home/...'

git affichera automatiquement la commande à exécuter.

  • Refresh index

Windows et Linux scannent les fichiers de façon différente. Ainsi, l'utilisation de git status en alternant entre Windows et WSL va créer une regénération du status à chaque changement.

git config core.checkStat minimal

git forces refresh index after switching between Windows and Linux Archive du 27/11/2019 le 05/01/2023

Ne pas télécharger l'historique

Pratique pour ne faire que de la compilation et alléger le téléchargement. Ajouter --depth 1 après git clone.

Télécharger uniquement une seule branche

git clone --single-branch --branch llvmorg-8.0.0 https://github.com/llvm/llvm-project.git

Un dépôt global ou un dépôt par projet / dépendance

C'est l'éternel débat. Est-il mieux d'avoir un projet par dépendance internes ou un unique projet global.

Ici, je suppose qu'il y a une équipe d'une trentaine de personnes qui travaille sur le même projet.

De par mon expérience, je conseille un projet par librairie / exécutable générée mais chaque choix a ses avantages / inconvénients.

Problématique Un projet par dépendance Un projet unique
X V Y V
Nombres de dépôts git Nombreux dépôts git. Un seul dépôt git.
Gestion des submodules Nécessite un super projet uniquement pour gérer la version des submodules. Pas de super projet.
Chaque super projet peut avoir une version différente des submodules en cas de modification d'API. Un changement d'API nécessite une modification de tous les autres composants dépendants.
Hétérogénéité des versions des submodules (dette technique). Les submodules sont toujours à jour.
Travail en groupe git submodule foreach git fetch est nécessaire pour savoir si des sous-modules ont évolués Les submodules sont toujours à jour.
Il y a moins de risque de conflit lors du commit des dépendances mais toujours autant dans le super projet. Mais dans le super projet, le fetch + checkout remet à jour les dépots et pas besoin de merge / rebase. Fetch / merge / rebase souvent nécessaire lors des commits
Pour appliquer une modification, il faut faire un commit dans la dépendance et un second dans le super projet Un seul commit est nécessaire.

Conclusion : si l'équipe n'est pas trop grande, je conseillerais un seul super projet. Si l'équipe est très grande avec plusieurs très gros projet (ayant des dépendances en commun) et de nombreux commits (ce qui nécessiterait un rebase à chaque fois), il est nécessaire de multiplier les dépôts. Dans ce dernier cas, il sera nécessaire de commencer par stabiliser l'interface de chaque composant pour ne pas être obligé de passer son temps à suivre les mises à jour des submodules ou encore pouvoir mettre à jour facilement un vieux projet auparavant abandonné.

Changer l'adresse d'un dépôt

Pour connaître l'adresse actuelle :

git remote -v

Pour la modifier :

git remote set-url origin https://github.com/USERNAME/OTHERREPOSITORY.git

Changing a remote's URL - User Documentation Archive le 22/10/2019

Déplacer un dossier vers au nouveau dépôt

Il faut créer un double du clone du dépôt car c'est le dossier du dépôt en cours qui va être converti vers un nouveau dépôt.

Splitting a subfolder out into a new repository Archive le 22/10/2019

Fusionner deux dépôts en un seul

Depuis le projet A :

git remote add -f Bproject path/to/B
git merge -s ours --no-commit --allow-unrelated-histories Bproject/master
rm -Rf path/to/B
git read-tree --prefix=path/to/B -u Bproject/master
git commit -m "Merge B project as our subdirectory"

Supprimer le submodule des fichiers .gitmodules, .git/config et supprimer le dossier .git/modules/path/to/B

git add .gitmodules
git commit -m "Remove submodule B project"

Git merge submodule into parent tree cleanly and preserving commit history Archive du 27/04/2014 le 22/09/2023

Ou

cd main
# Cette commande doit impérativement être lancée depuis la racine du dépôt git et pas à l'emplacement du futur nouveau dossier.
git fetch ../other master:tmp
git checkout tmp
git filter-branch --index-filter \
    'git ls-files -s | sed "s-\t\"*-&sub/-" |
        GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
            git update-index --index-info &&
     mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"'
git rebase master
git checkout master
git merge tmp
git branch -d tmp
git update-ref -d refs/original/refs/heads/tmp

Fusionner deux dépôts git Archive du 12/07/2017 le 22/10/2019

Dupliquer un dépôt

Il faut commencer par le cloner si ce n'est pas déjà fait.

git clone --bare https://github.com/exampleuser/old-repository.git

L'option --bare télécharge uniquement le dépôt sans faire le checkout.

cd old-repository
git lfs fetch --all
git push --mirror https://github.com/exampleuser/new-repository.git
git lfs push --all https://github.com/exampleuser/new-repository.git

Duplicating a repository Archive du 25/02/2022 le 12/09/2022

Branches

Mettre à jour une branche qui s'est éloignée du maître

Update Git branches from master Archive du 06/10/2010 le 22/10/2019

# Récupère les dernières modifications du serveur
git fetch
# Synchronise les deux branches.
git rebase origin/master

Cela annule les modifications de la branche, applique les modifications du maître puis applique à nouveau les commits de la branche.

Manipulation

  • Création d'un nouvelle branche :
git branch branche
  • Changer de branche :
git checkout branche
  • Pousser une branche :
git push -u origin branche
  • Renommer une branche :
git branch -m old-name new-name
git branch new-name --set-upstream-to origin/new-name
git push origin --delete old-name
git push -u origin new-name
  • Déplacer l'extrémité d'une branche vers une autre (en altérant l'historique mais sans créer de nouveau commit)
git checkout master
git reset --hard branche
  • Intégrer l'extrémité d'une branche vers une autre (sans altérer l'historique mais en créant un nouveau commit)
git checkout master
git merge branche

Gestion des conflits lors d'un push

git push --force-with-lease

En cas de conflit lors d'un push, l'utilisation de --force-with-lease va modifier les commits sur le dépôt pour que la branche distante corresponde à celle en locale.

Il est interdit d'utiliser --force. Cela peut effacer le travail des autres car --force-with-lease va vérifier que la branche locale est synchro avec la branche distance. Si on ne vérifie pas la branche distance (avec --force), on peut effacer le travail des autres.

Commit

Tags

Suppression d'un tag déjà push

git tag -d XXXX
git push origin :refs/tags/XXXX

Push d'un tag

git push origin --tags

Annulation d'une modification non encore "commitée"

git checkout -- <fichier>

Afficher les différences

Avant git add

git diff

Après git add

git diff --cached

Taille du contexte (nombre de lignes avant et après une modification) : -U10

Trouver le commit à l'origine d'un bug

git bisect start
git bisect good HEAD
git bisect bad 0123456789abcdef

Ensuite, il faut compiler puis indiquer manuellement :

  1. git bisect good si le code est bon,
  2. git bisect bad si le code est faux,
  3. git bisect skip s'il est impossible d'évaluer le commit (erreur de compilation par exemple).

Il est aussi possible d'automatiser par un script l'évaluation du commit. Exemple avec cmake :

script.sh
rm -Rf build
mkdir build
cd build
cmake .. || exit 125
make -j9 || exit 125
./utils/pdftohtml /tmp/abort_on_dead_object.pdf /tmp/ii || exit 1
exit 0
  1. exit 125 signifie que le commit doit être ignoré.
  2. exit 1 signifie que le commit est invalide.

On lance la recherche avec git bisect run ./script arg

Il est théoriquement inutile de supprimer le dossier de compilation et de repartir à chaque fois à 0. Mais, parfois, le système de compilation (autotools) se trompe dans les dépendances et ne recompile pas tout ce qui devrait l'être. Cela crée des bugs à l'exécution qui n'en sont pas forcément.

Se resynchroniser après qu'un projet ait accepté la pull request

Ou le syndrome github du This branch is X commits behind. Depuis le dépôt cloné :

git remote add upstream git://github.com/ORIGINAL-DEV-USERNAME/REPO-YOU-FORKED-FROM.git
git fetch upstream
git checkout master
git merge upstream/master

Configuring a remote for a fork - User Documentation Archive le 22/10/2019

Syncing a fork - User Documentation Archive le 22/10/2019

Changer le message de tous les commit automatiquement

git filter-branch -f --msg-filter 'sed "s/^git-svn-id.*$//"' -- --all

Cela enlève toutes les lignes commençant par git-svn-id pour tous les commits -- --all.

Importer un commit depuis un autre dépôt

Il faut ajouter le nouveau dépôt, faire un fetch puis utiliser la commande cherry-pick.

Le hash va automatiquement être cherché dans tous les dépôts disponibles.

git add remote XXXXX https://github.com/XXXXX/anotherrepo.git
git fetch XXXXX/master
git cherry-pick -x SHA

How to take commits from a different repository : Git cherry-pick & format-patch Archive 02/10/2015 le 22/10/2019

Il peut y avoir des problèmes sur des fichiers ont été renommés et que git n'arrive pas à détecter. Alors, il faut utiliser -Xrename-threshold=5% pour réduire le seuil de tolérance.

git cherry-pick -Xrename-threshold=5% -x SHA

Importer seulement un fichier d'un commit

Modifier la date / auteur du commit initiale

Pour changer l'auteur, il suffit de rajouter --amend --author="Author Name <email@address.com>".

Ci-dessous, on amende un commit en le signant (GPG) et en utilisant le message par défaut

GIT_COMMITTER_DATE='2020-10-27T06:50:12' git commit --date '2020-10-27T06:50:12' -S --amend

Ne pas utiliser GIT_AUTHOR_DATE à la place de --date, cela ne fonctionne pas.

--date spécifie la date de création du commit. GIT_COMMITTER_DATE est la date du push.

How do I make a Git commit in the past? Archive du 09/10/2010 le 24/09/2020

Mais attention, en cas de signature avec une clé GPG, la date du commit sera toujours l'actuelle.

Subtree

Les subtree utilisent les remote plutôt que les submodules.

Ajout d'un subtree

git remote add -f name url_repository
git subtree add --prefix folder url_repository branch

avec :

  • folder : le dossier qui contiendra le subtree,
  • url_repository : l'url de dépôt git du subtree,
  • branch : la branch (master par exemple).

Dans le cas d'une architecture subtree, l'historique des subtree est ajouté au super projet. Si ce n'est pas souhaité, il faut ajouter --squash

git subtree add ne fonctionne que sur un dépôt ayant déjà au moins un commit.

pusher un subtree

Faire un commit de façon traditionnelle.

La technique consiste à pusher sur les dépôts distants puis à synchroniser le dépôt principal.

git subtree push --prefix=folder remote_name branch

Mais en faisant simplement çà, on se retrouve avec des commits différents entre le dépot principal et le dépot subtree. Il faut donc les synchroniser à nouveau :

Récupérer les modifications d'une branche

git subtree pull --prefix=folder remote_name branch

Et c'est très moche dans l'historique de git :

Historique git avec subtree et plusieurs branches

En plus, dans le pull, on ne peut pas faire un commit pour deux branches distinctes.

Je ne comprends pas pourquoi les subtree sont considérés par certains comme mieux que les submodules.

Comprendre et maîtriser les subtrees Git Archive du 30/01/2015 le 07/10/2019

Git subtree: une alternative à Git submodule Archive du 15/05/2019 le 08/10/2019

Git subtree or how I stopped worrying and learned to love external dependencies Archive du 27/11/2018 le 21/11/2019

Historique

Chercher dans le code sur l'ensemble des commits

git grep <regexp> $(git rev-list --all)

Attention, cela cherche dans tous les fichiers, pas uniquement dans les modifications du commit.

Chercher dans le code uniquement les modifications

git log -S"a chercher"

Trouver le commit qui supprime un fichier

Il n'y a pas moyen. Mais on peut retrouver tous les commits modifiant un fichier précis.

git log --full-history -- your_file

Le dernier sera celui l'ayant supprimé.

Chercher une modification également dans les sous-modules

git submodule foreach git log -S"Pattern"

Annuler temporairement des modifications

Les modifications sont stockés sous forme d'une liste FILO.

  • Stocke les modifications dans une zone nom_memoire.
git stash push -m nom_memoire fichiers
  • Restaure les modifications
git stash apply
# Il est possible d'appliquer les modifications sans enlever la dernière zone mémoire.
git stash drop
 
# Ou il est possible de tout faire en même temps.
git stash pop

Ignorer certains commits avec blame

Inscrire les numéros de commit (un par ligne) dans un fichier .git-blame-ignore-revs.

Modifier une liste de commits

Applique clang-format pour tous les fichiers .cpp ayant changés.

git filter-branch --tree-filter 'git-clang-format $(\
  git diff-index --diff-filter=AM --name-only $GIT_COMMIT |\
    grep .cpp)' -- <SHA1>..HEAD

Run git-clang-format on series of git commits Archive du 15/05/2017 le 27/03/2023

État du dépôt

bash

  • Si des fichiers ont été modifiés
if [[ ! -z "$(git status --porcelain)" ]]
then
  echo "Some files has been modified."
  exit 1
fi;

Pour utiliser git diff-index --name-only HEAD --, il est nécessaire d'appeler git update-index --refresh. Why does git diff-index HEAD result change for touched files after git diff or git status? Archive du 15/01/2016 le 19/01/2024

  • Si des fichiers non ignorés ont été ajoutés
if [ -n "$(git ls-files --others --exclude-standard)" ]

Maintenance

Vérifie l'état d'un dépôt

git fsck --no-dangling
$ git fsck --no-dangling
error: corrupt loose object '2a9e451f85ba5e26dbe34d742105e877b0942570'
error: unable to unpack contents of .git/objects/2a/9e451f85ba5e26dbe34d742105e877b0942570
error: 2a9e451f85ba5e26dbe34d742105e877b0942570: object corrupt or missing: .git/objects/2a/9e451f85ba5e26dbe34d742105e877b0942570
Checking object directories: 100% (256/256), done.
Checking objects: 100% (812/812), done.
missing tree 2a9e451f85ba5e26dbe34d742105e877b0942570

Savoir à quel commit appartient un blob

git log --raw --all --find-object=<blob hash>

Suppression des dangling blobs

Ces commits inachevés sont détectés par la commande

git fsck
git reflog expire --expire-unreachable=now --expire=now --all --dry-run
git reflog expire --expire-unreachable=now --expire=now --all
git gc --prune=now
git repack

git_ dangling blobs - Stack Overflow Archive du 31/03/2012 le 22/10/2019

Ne garder que la dernière version après un git pull

git checkout --orphan master
git gc --prune=all

Supprimer un submodule

  • git submodule deinit <path_to_submodule>
  • git rm <path_to_submodule>
  • git commit-m "Removed submodule"
  • rm -rf .git/modules/<path_to_submodule>

How effectively delete a git submodule? Archive du 18/07/2018 le 22/10/2019

Changer l'url/remote d'un submodule

git submodule set-url -- <local_path> <new_url>

Signer tous les commits existants

git filter-branch -f --commit-filter 'git commit-tree -S "$@"' HEAD
git push -f

Git sign off previous commits? Archive du 24/10/2012 le 22/10/2019

Supprimer les branches locales qui ont été supprimées sur le dépôt distant

git fetch -p
git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d

How to prune local tracking branches that do not exist on remote anymore? Archive du 25/10/2012 le 20/03/2023

Clés publiques / privées

Pour signer les commits, il faut commencer par avoir la clé publique et privée.

Génération de la clé

gpg --full-generate-key

Choisir une clé RSA et RSA de la taille maximale (4096).

Afficher la clé publique et privée

gpg --list-secret-keys --keyid-format LONG

Avec YYYYYYYYY l'id de la ligne sec rsa4096/YYYYYYYYY

Pour exporter la clé publique :

gpg --armor --export YYYYYYYYY

Pour exporter la clé privée :

gpg --export-secret-keys YYYYYYYYY > file.key

Configurer git

Pour importer une clé privée :

gpg --import file.key

Si on souhaite ajouter la signature des commits pour tous les projets.

git config --global user.signingkey YYYYYYYYY
git config --global commit.gpgsign true

Mettre à jour la clé

Il faut connaître le numéro de la clé.

gpg --list-keys --keyid-format=long

Le numéro de la clé est celui du pub après l'algorithme (NUMERONUMERONUEM ci-dessous).

pub   rsa4096/NUMERONUMERONUEM 2020-08-09 [SC] [expires: 2022-08-11]  
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid                 [ unknown] USERNAME <mail@example.com>
sub   rsa4096/XXXXXXXXXXXXXXXX 2020-08-09 [E] [expires: 2022-08-11]   

Date d'expiration

Pour mettre à jour la date d'expiration, il faut faire :

gpg --edit-key KEY_ID
list
key 0
expire
key 1
expire
save

Ne pas choisir une date d'expiration supérieure à 1 an. C'est la limite de sécurité généralement considérée comme sûr.

Pour la mettre à jour sur GitHub, il faut supprimer la clé publique précédente avant de la rajouter. Sinon GitHub détecte que la clé publique a déjà été importée mais il ne détecte pas le changement de date.

What to do when your GPG/PGP key expires Archive du 2013 le 11/08/2021

Messages d'erreur

warning: unable to rmdir 'XXXX': Directory not empty

C'est généralement affiché lors d'un checkout. Cela signifie qu'un module a été supprimé mais que git a décidé de ne pas supprimer le dossier. Il suffit de le supprimer manuellement.

warning: you may want to set your XXX variable to at least YYY and retry the command.

git config XXX YYY

git describe

  • No names found, cannot describe anything

Ajouter un tag git tag foo.

  • No annotated tags can describe

Ajouter un tag annoté git tag -a 'annotated-tag' -m 'whatever'.

Jenkins Git plugin: git describe cannot describe anything Archive du 22/04/2012 le 22/10/2019

fatal: unable to find remote helper for 'https'

Pour cloner des dépôts en https://github.com/xxx, il faut compiler git avec le support de curl.

SSL certificate problem: unable to get local issuer certificate

fatal: unable to access 'xxxxx.git/': error setting certificate file: xxxx\CI_SERVER_TLS_CA_FILE

L'option credential.helper est configuré à store et le mot de passe défini dans le fichier .git-credentials est faux.

Windows

Github

Personal access token

Pour pouvoir pousser sur un dépôt en utilisant un token plutôt que le mot de passe du site, il faut :

  • Générer le token dans les settings de l'utilisateur,
  • Créer un nouveau token avec les droits : read:org, repo, user:email, workflow (si le dépôt contient un dossier .workflow),
  • Noter la clé,
  • Puis, au moment de faire un push, mettre le nom d'utilisateur puis le token (pas le mot de passe de connexion de github). Il faut aussi faire attention que l'adresse de push est bien en https:// et pas en git://.

Third party

Gource

Programme de visualisation sous forme de vidéos des dépôts github. Site web Archive v0.51 x64

Le dépôt est représenté sous forme d'un arbre. Le dossier est une branche et les fichiers sont des feuilles.

Puis on voit où chaque contributeur contribue au fil du temps.

Commandes Videos Archive du 21/08/2018 le 28/12/2020

gource -1280x720 -o gource.ppm
ffmpeg -y -r 60 -f image2pipe -vcodec ppm -i gource.ppm -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -crf 24 -threads 8 gource.mp4

Attention, l'encodage est mauvais dans les dégradés sombres. Il faudra accepter une vidéo de faible taille avec des carrés ou mettre un crf très faible (< 15) avec une vidéo de très grosse taille.

prog/git.txt · Dernière modification : 2024/08/19 10:36 de root