=====Téléchargement=====
====Windows====
[[https://gitforwindows.org|Site Web]], {{ :prog:git:git-2.21.0-64-bit.exe |Archive git gui 64 bit 2.21.0 (26/02/2019)}}
[[http://matthew-brett.github.io/pydagogue/git_gui_windows.html|Getting started with git gui on Windows]] {{ :prog:git:getting_started_with_git_gui_on_windows_pydagogue_0.2_documentation_2019-10-22_13_33_19_.html |Archive le 22/10/2019}}
=====Dépôts=====
====Configurer====
===Options globales===
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
git config --global user.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
[[prive:prog:git|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
[[https://linuxhint.com/save-username-password-in-git/|How to Save Username and Password in Git]] {{ :prog:git:how_to_save_username_and_password_in_git_14_10_2022_13_46_20_.html |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
[[https://stackoverflow.com/questions/59061816/git-forces-refresh-index-after-switching-between-windows-and-linux|git forces refresh index after switching between Windows and Linux]] {{ :prog:git:git_forces_refresh_index_after_switching_between_windows_and_linux_-_stack_overflow_05_01_2023_11_14_41_.html |Archive du 27/11/2019 le 05/01/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 (sign only)'' de la taille maximale (4096). ''RSA'' signe plus rapidement que ''DSA'' (qui vérifie plus rapidement). Dans mon cas, ce qui m'intéresse, c'est que les commits soient signés rapidement sur ma machine.
====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
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.
[[https://makandracards.com/makandra-orga/13644-what-to-do-when-your-gpg-pgp-key-expires|What to do when your GPG/PGP key expires]] {{ :prog:git:what_to_do_when_your_gpg_pgp_key_expires_-_makandra_orga_2021-08-11_20_28_16_.html |Archive du 2013 le 11/08/2021}}
====Cloner====
git clone https://github.com/bansan85/2lgc.git
* 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
====Dupliquer un dépôt contenant du lfs====
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
[[https://docs.github.com/en/repositories/creating-and-managing-repositories/duplicating-a-repository|Duplicating a repository]] {{ :prog:git:duplicating_a_repository_-_github_docs_12_09_2022_12_48_10_.html |Archive du 25/02/2022 le 12/09/2022}}
=====Submodules=====
====Supprimer un submodule====
git submodule deinit
git rm
git commit -m "Removed submodule"
rm -rf .git/modules/
[[https://gist.github.com/myusuf3/7f645819ded92bda6677#gistcomment-2650640|How effectively delete a git submodule?]] {{ :prog:git:how_effectively_delete_a_git_submodule._github_2019-10-22_13_32_38_.html |Archive du 18/07/2018 le 22/10/2019}}
====Changer l'url/remote d'un submodule====
git submodule set-url --
=====Branches=====
====Mettre à jour une branche qui s'est éloignée du maître====
[[https://stackoverflow.com/questions/3876977/update-git-branches-from-master|Update Git branches from master]] {{ :prog:git:git_branch_-_update_git_branches_from_master_-_stack_overflow_2019-10-22_13_30_54_.html |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
{{:prog:git:git_merge.png?350|}}
====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.
====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
[[https://help.github.com/articles/configuring-a-remote-for-a-fork/|Configuring a remote for a fork - User Documentation]] {{ :prog:git:configuring_a_remote_for_a_fork_-_github_help_2019-10-22_13_31_02_.html |Archive le 22/10/2019}}
[[https://help.github.com/articles/syncing-a-fork/|Syncing a fork - User Documentation]] {{ :prog:git:syncing_a_fork_-_github_help_2019-10-22_13_31_08_.html |Archive le 22/10/2019}}
=====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 --
====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 :
- ''git bisect good'' si le code est bon,
- ''git bisect bad'' si le code est faux,
- ''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'' :
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
- ''exit 125'' signifie que le commit doit être ignoré.
- ''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.
====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
[[http://voidcanvas.com/cherry-pick-format-patch/|How to take commits from a different repository : Git cherry-pick & format-patch]] {{ :prog:git:how_to_take_commits_from_a_different_repository_git_cherry-pick_format-patch_void_canvas_2019-10-22_13_31_15_.html |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====
git show SHA -- file1.txt file2.txt | git apply -
[[https://stackoverflow.com/questions/5717026/how-to-git-cherry-pick-only-changes-to-certain-files|How to git-cherry-pick only changes to certain files?]] {{ :prog:git:github_-_how_to_git-cherry-pick_only_changes_to_certain_files_-_stack_overflow_2019-10-22_13_31_27_.html |Archive du 19/04/2011 le 22/10/2019}}
====Modifier la date / auteur du commit initiale====
Pour changer l'auteur, il suffit de rajouter ''%%--amend --author="Author Name "%%''.
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.
[[https://stackoverflow.com/questions/3895453/how-do-i-make-a-git-commit-in-the-past|How do I make a Git commit in the past?]] {{ :prog:git:version_control_-_how_do_i_make_a_git_commit_in_the_past_-_stack_overflow_2020-09-24_11_32_10_.html |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.
====Signer tous les commits existants====
Cela réécrit tout l'arbre git.
git filter-branch -f --commit-filter 'git commit-tree -S "$@"' HEAD
git push -f
[[https://stackoverflow.com/questions/13043357/git-sign-off-previous-commits|Git sign off previous commits?]] {{ :prog:git:git_sign_off_previous_commits_-_stack_overflow_2019-10-22_13_32_56_.html |Archive du 24/10/2012 le 22/10/2019}}
====Avoir tous les enfants d'un commit====
find_descendants() {
local sha=$1
line=$(git rev-list --all --children | grep ^$sha)
if [[ $line == *" "* ]]; then
children=$(echo $line | cut -d' ' -f2-)
for child in $children; do
echo $child
find_descendants $child
done
fi
}
find_descendants $1
=====État du dépôt=====
====Si des fichiers ont été modifiés====
if [[ ! -z "$(git status --porcelain --ignore-submodules)" ]]
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%%''. [[https://stackoverflow.com/questions/34807971/why-does-git-diff-index-head-result-change-for-touched-files-after-git-diff-or-g|Why does git diff-index HEAD result change for touched files after git diff or git status?]] {{ :prog:git:why_does_git_diff-index_head_result_change_for_touched_files_after_git_diff_or_git_status_-_stack_overflow_1_19_2024_4_04_53_pm_.html |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=====
====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
[[https://help.github.com/articles/changing-a-remote-s-url/|Changing a remote's URL - User Documentation]] {{ :prog:git:changing_a_remote_s_url_-_github_help_2019-10-22_13_30_20_.html |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.
[[https://help.github.com/articles/splitting-a-subfolder-out-into-a-new-repository/|Splitting a subfolder out into a new repository]] {{ :prog:git:splitting_a_subfolder_out_into_a_new_repository_-_github_help_2019-10-22_13_30_27_.html |Archive le 22/10/2019}}
====Fusionner deux dépôts en un seul et en conservant l'historique====
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"
[[https://stackoverflow.com/questions/23327701/git-merge-submodule-into-parent-tree-cleanly-and-preserving-commit-history|Git merge submodule into parent tree cleanly and preserving commit history]] {{ :prog:git:git_merge_submodule_into_parent_tree_cleanly_and_preserving_commit_history_-_stack_overflow_22_09_2023_12_24_09_.html |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
[[https://blog.rom1v.com/2017/07/fusionner-deux-depots-git/|Fusionner deux dépôts git]] {{ :prog:git:fusionner_deux_depots_git_rom1v_blog_2019-10-22_13_30_34_.html |Archive du 12/07/2017 le 22/10/2019}}
====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=
et pour un objet LFS
git log -S
====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
[[https://stackoverflow.com/questions/9955713/git-dangling-blobs|git_ dangling blobs - Stack Overflow]] {{ :prog:git:git_dangling_blobs_-_stack_overflow_2019-10-22_13_32_16_.html |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 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
Bien mettre à jour ''main''. Et faire un test en enlevant la commande ''xargs ...''.
[[https://stackoverflow.com/questions/13064613/how-to-prune-local-tracking-branches-that-do-not-exist-on-remote-anymore|How to prune local tracking branches that do not exist on remote anymore?]] {{ :prog:git:git_-_how_to_prune_local_tracking_branches_that_do_not_exist_on_remote_anymore_-_stack_overflow_20_03_2023_10_21_42_.html |Archive du 25/10/2012 le 20/03/2023}}
=====Historique=====
====Chercher dans le code sur l'ensemble des commits====
git grep $(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"
====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%%''.
====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)' -- ..HEAD
[[https://stackoverflow.com/questions/43974371/run-git-clang-format-on-series-of-git-commits|Run git-clang-format on series of git commits]] {{ :prog:git:formatting_-_run_git-clang-format_on_series_of_git_commits_-_stack_overflow_27_03_2023_10_03_57_.html |Archive du 15/05/2017 le 27/03/2023}}
=====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 :
{{:prog:git:git_historique_subtree.png|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.
[[https://delicious-insights.com/fr/articles/git-subtrees/|Comprendre et maîtriser les subtrees Git]] {{ :prog:git:comprendre_et_maitriser_les_subtrees_git_delicious_insights_2019-10-07_23_58_57_.html |Archive du 30/01/2015 le 07/10/2019}}
[[https://gauthier.frama.io/post/git-subtree/|Git subtree: une alternative à Git submodule]] {{ :prog:git:git_subtree_une_alternative_a_git_submodule_le_blog_de_gauthier_2019-10-07_00_00_35_.html |Archive du 15/05/2019 le 08/10/2019}}
[[https://tsh.io/blog/git-subtree-or-how-i-stopped-worrying-and-learned-to-love-external-dependencies/|Git subtree or how I stopped worrying and learned to love external dependencies]] {{ :prog:git:how_i_learned_to_love_external_dependencies_tsh.io_2019-11-21_10_43_04_.html |Archive du 27/11/2018 le 21/11/2019}}
=====Best partices=====
====Un dépôt global ou un dépôt par projet / dépendance====
Je conseille un projet par librairie / projet.
L'utilisation d'un projet unique impose à cloner tout, y compris des projets et dépendances dont on n'a pas besoin.
===Nombres de dépôts===
Séparer les dépôts réduit le nombre de dépendances de chaque projet car chaque projet n'importe que ses dépendances.
Mais avoir de nombreux projets nécessite plus de travail pour la synchronisation et pour la publication officielles des versions.
===Gestion des dépendances===
* Super projet contenant les submodules à la racine
Exemple [[https://github.com/boostorg/boost/tree/master/libs|Boost]]. Les librairies n'ont pas de submodule.
Inconvénients :
- Nécessite un super projet pour compiler. Au choix : soit un super projet qui clone tout (Boost), soit un super projet par projet à compiler.
- Dépendances circulaires difficilement détectables entre projets.
* Submodule dans chaque projet
Inconvénients :
- Clonage récursif infini si dépendances circulaires.
- Si 2 librairies dépendent d'une même 3ème, la 3ème peut être a des versions différentes sur les 2 premières librairies.
* Gestionnaire externe (vcpkg)
Inconvénients :
- Travail supplémentaire pour maintenir les ports vcpkg. Dans le cas de vcpkg, il faut créer un port par branche de dev et l'utiliser en mode ''%%--head%%''.
- Si on travaille sur des dépendances, ça oblige à commiter à chaque test et vcpkg doit tout recompiler.
====Rebase / amend / force push====
Faut-il autoriser les rebases ou non ? Il y a 2 parties irréconciliables : avoir un arbre git propre (et autoriser les rebases) et avoir un arbre qui mémorise l'évolution de l'écriture du code (et interdir les rebases).
===Retravailler l'historique===
* Sur les branches de développement
Je suis pour les modifications. C'est un espace de travail et de bac à sable qui peut être utilisé pour tester le code sur la CI. De plus, ça permet de sauvegarder le code quotidiennement et de voir l'état de la CI.
⚠️ Autoriser de retravailler une branche interdit de se greffer sur une branche de développement d'un dépôt enfant. La branche de développement de l'autre dépôt peut aussi être retravaillée. On risque de se retrouver avec un historique des commits inutilisables dans la branche de developpement du dépôt parent.
Par contre, il ne faut fusionner que les commits qui concerne une même tâche et ne pas fusionner tout l'historique (squash) pour avoir l'historique le plus petit possible.
* Modifier le commit de base d'une racine
Lors d'un merge, il faut utiliser ''%%--no-ff%%'' afin de garder visuellement la branche dans l'arbre git.
L'intérêt de modifier le commit de base est d'éviter d'avoir un arbre git qui ressemble à ça.
{{:prog:git:git-large-tree.png?650|}}
Mais plutôt d'avoir :
{{:prog:git:git-thin-tree.png?427|}}
Oui, c'est plus joli. Mais est-ce c'est nécessaire de l'imposer ?
Si beaucoup de personnes travaillent en même temps sur le projet, l'imposer est ingérable. Peut-être l'imposer si le commit de base a plus d'une semaine / un mois par rapport au commit le plus récent dans la branche de destination ?
S'il n'y a pas de conflit lors du merge, ne pas l'imposer.
En cas de conflit lors du merge, il ne faut pas résoudre le conflit en local avant de merger. Sinon, la résolution des conflits seront dans le commit de merge et c'est contre-intuitif de lire le commit de merge pour lire les modifications.
{{:prog:git:git-merge-conflict.png?808|}}
Il faut appliquer la technique de Gitlab avec le double merge. On merge la branche de destination vers la branche de dev pour résoudre les conflits puis on merge la branche de dev vers la branche de destination. Il y a toujours un commit de merge qui contient la résolution des conflits mais il est séparé du commit de merge final.
{{:prog:git:git-merge-conflict-2.png?419|}}
On peut aussi faire des rebases régulièrement afin d'éviter d'avoir trop de conflits à gérer. Mais il peut être plus facile de résoudre tous les conflits en une fois.
=====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%%'%%''.
[[https://stackoverflow.com/questions/10268641/jenkins-git-plugin-git-describe-cannot-describe-anything|Jenkins Git plugin: git describe cannot describe anything]] {{ :prog:git:python_-_jenkins_git_plugin_git_describe_cannot_describe_anything_-_stack_overflow_2019-10-22_13_33_07_.html |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====
Sous Windows :
git config --global http.sslbackend schannel
[[https://stackoverflow.com/questions/23885449/unable-to-resolve-unable-to-get-local-issuer-certificate-using-git-on-windows|Unable to resolve "unable to get local issuer certificate" using git on Windows with self-signed certificate]] {{ :prog:git:unable_to_resolve_unable_to_get_local_issuer_certificate_using_git_on_windows_with_self-signed_certificate_-_stack_overflow_27_02_2023_16_06_21_.html |Archive du 27/05/2015 le 27/02/2023}}
====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.
====error: object file .git/objects/a3/02c397c3b0c0c8959b35778c1705a89108fdb2 is empty====
Pour éviter de devoir tout cloner à nouveau et devoir tout recompiler, il faut tester :
find .git/objects/ -size 0 -delete
git fetch
[[https://stackoverflow.com/questions/4111728/how-do-i-deal-with-corrupted-git-object-files|How do I deal with corrupted Git object files?]] {{ :prog:git:how_do_i_deal_with_corrupted_git_object_files_-_stack_overflow_28_12_2024_22_04_15_.html |Archive du 06/11/2010 le 28/12/2024}}
====gpg: keydb_search failed: Invalid argument====
gpg: keydb_search failed: Invalid argument
gpg: skipped "XXXXXXXXXXXXXXXX": Invalid argument
[GNUPG:] INV_SGNR 0 XXXXXXXXXXXXXXXX
[GNUPG:] FAILURE sign XXXXXXXXX
gpg: signing failed: Invalid argument
Supprimer le dossier ''~/.gnupg'' et réimporter les clés privées.