-
1. Démarrage rapide
-
2. Les bases de Git
-
3. Les branches avec Git
-
4. Git sur le serveur
- 4.1 Protocoles
- 4.2 Installation de Git sur un serveur
- 4.3 Génération des clés publiques SSH
- 4.4 Mise en place du serveur
- 4.5 Démon (Daemon) Git
- 4.6 HTTP intelligent
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Git hébergé
- 4.10 Résumé
-
5. Git distribué
-
6. GitHub
-
7. Utilitaires Git
- 7.1 Sélection des versions
- 7.2 Indexation interactive
- 7.3 Remisage et nettoyage
- 7.4 Signer votre travail
- 7.5 Recherche
- 7.6 Réécrire l’historique
- 7.7 Reset démystifié
- 7.8 Fusion avancée
- 7.9 Rerere
- 7.10 Déboguer avec Git
- 7.11 Sous-modules
- 7.12 Empaquetage (bundling)
- 7.13 Replace
- 7.14 Stockage des identifiants
- 7.15 Résumé
-
8. Personnalisation de Git
- 8.1 Configuration de Git
- 8.2 Attributs Git
- 8.3 Crochets Git
- 8.4 Exemple de politique gérée par Git
- 8.5 Résumé
-
9. Git et les autres systèmes
- 9.1 Git comme client
- 9.2 Migration vers Git
- 9.3 Résumé
-
10. Les tripes de Git
- 10.1 Plomberie et porcelaine
- 10.2 Les objets de Git
- 10.3 Références Git
- 10.4 Fichiers groupés
- 10.5 La refspec
- 10.6 Les protocoles de transfert
- 10.7 Maintenance et récupération de données
- 10.8 Les variables d’environnement
- 10.9 Résumé
-
A1. Annexe A: Git dans d’autres environnements
- A1.1 Interfaces graphiques
- A1.2 Git dans Visual Studio
- A1.3 Git dans Visual Studio Code
- A1.4 Git dans IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git dans Sublime Text
- A1.6 Git dans Bash
- A1.7 Git dans Zsh
- A1.8 Git dans PowerShell
- A1.9 Résumé
-
A2. Annexe B: Embarquer Git dans vos applications
- A2.1 Git en ligne de commande
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Commandes Git
- A3.1 Installation et configuration
- A3.2 Obtention et création des projets
- A3.3 Capture d’instantané basique
- A3.4 Création de branches et fusion
- A3.5 Partage et mise à jour de projets
- A3.6 Inspection et comparaison
- A3.7 Débogage
- A3.8 Patchs
- A3.9 Courriel
- A3.10 Systèmes externes
- A3.11 Administration
- A3.12 Commandes de plomberie
7.13 Utilitaires Git - Replace
Replace
Git manipule des objets immuables mais il fournit un moyen de faire comme s’il pouvait remplacer des objets de sa base de données par d’autres objets.
La commande replace
vous permet de spécifier un objet dans Git et de lui indiquer : « chaque fois que tu vois ceci, fais comme si c’était cette autre chose ».
Ceci sert principalement à remplacer un commit par un autre dans votre historique.
Par exemple, supposons que vous avez un énorme historique de code et que vous souhaitez scinder votre dépôt en un historique court pour les nouveaux développeurs et un plus important et long pour ceux intéressés par des statistiques.
Vous pouvez générer un historique depuis l’autre avec replace
en remplaçant le commit le plus ancien du nouvel historique par le dernier commit de l’historique ancien.
C’est sympa parce que cela signifie que vous n’avez pas besoin de réécrire tous les commits du nouvel historique, comme vous devriez le faire pour les joindre tous les deux (à cause de l’effet de lien des SHA-1).
Voyons ce que ça donne.
Prenons un dépôt existant, découpons-le en deux dépôts, un récent et un historique, puis nous verrons comment les recombiner sans modifier les valeurs SHA-1 du dépôt récent, grâce à replace
.
Nous allons utiliser un dépôt simple avec cinq commit simples :
$ git log --oneline
ef989d8 fifth commit
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Nous souhaitons couper ceci en deux lignes d’historiques. Une ligne ira de first commit à fourth commit et sera la ligne historique. La seconde ligne ira de fourth commit à fifth commit et sera ligne récente.
![replace1](png/replace1.png)
Bien, la création de la ligne historique est simple, nous n’avons qu’à créer une branche dans l’historique et la pousser vers la branche master
d’un nouveau dépôt distant.
$ git branch history c6e1e95
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
![replace2](png/replace2.png)
Maintenant, nous pouvons pousser la nouvelle branche history
vers la branche master
du nouveau dépôt :
$ git remote add project-history https://github.com/schacon/project-history
$ git push project-history history:master
Décompte des objets : 12, fait.
Delta compression using up to 2 threads.
Compression des objets : 100% (4/4), fait.
Écriture des objets : 100% (12/12), 907 bytes, fait.
Total 12 (delta 0), reused 0 (delta 0)
Dépaquetage des objets : 100% (12/12), fait.
To git@github.com:schacon/project-history.git
* [nouvelle branche] history -> master
Bien, notre projet historique est publié. Maintenant, la partie la plus compliquée consiste à tronquer l’historique récent pour le raccourcir. Nous avons besoin d’un recouvrement pour pouvoir remplacer un commit dans un historique par un équivalent dans l’autre, donc nous allons tronquer l’historique à fourth commit et fifth commit, pour que fourth commit soit en recouvrement.
$ git log --oneline --decorate
ef989d8 (HEAD, master) fifth commit
c6e1e95 (history) fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Il peut être utile de créer un commit de base qui contient les instructions sur la manière d’étendre l’historique, de sorte que les autres développeurs puissent savoir comment s’y prendre s’ils butent sur le premier commit et ont besoin de plus d’histoire. Donc, ce que nous allons faire, c’est créer un objet commit initial comme base avec les instructions, puis rebaser les commits restants (quatre et cinq) dessus.
Nous avons besoin de choisir un point de découpe, qui pour nous est third commit, soit le SHA-1 9c68fdc
.
Donc, notre commit de base sera créé sur cet arbre.
Nous pouvons créer notre commit de base en utilisant la commande commit-tree
, qui accepte juste un arbre et nous fournit un SHA-1 d’un objet commit orphelin tout nouveau.
$ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
622e88e9cbfbacfb75b5279245b9fb38dfea10cf
Note
|
La commande |
![replace3](png/replace3.png)
OK, donc maintenant avec un commit de base, nous pouvons rebaser le reste de notre historique dessus avec la commande git rebase --onto
.
L’argument --onto
sera l’empreinte SHA-1 que nous venons tout juste de récupérer avec la commande commit-tree
et le point de rebasage sera third commit
(le parent du premier commit que nous souhaitons garder, 9c68fdc
).
$ git rebase --onto 622e88 9c68fdc
First, rewinding head to replay your work on top of it...
Applying: fourth commit
Applying: fifth commit
![replace4](png/replace4.png)
Bien, nous avons donc réécrit l’historique récent à la suite du commit de base qui contient les instructions pour reconstruire l’historique complet. Nous pouvons pousser ce nouvel historique vers un nouveau projet et quand des personnes clonent ce dépôt, elles ne voient que les deux commits les plus récents et un commit avec des instructions.
Inversons les rôles et plaçons-nous dans la position d’une personne qui clone le projet pour la première fois et souhaite obtenir l’historique complet. Pour obtenir les données d’historique après avoir cloné ce dépôt tronqué, on doit ajouter un second dépôt distant pointant vers le dépôt historique et tout récupérer :
$ git clone https://github.com/schacon/project
$ cd project
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah
$ git remote add project-history https://github.com/schacon/project-history
$ git fetch project-history
From https://github.com/schacon/project-history
* [nouvelle branche] master -> project-history/master
À présent, le collaborateur aurait les commits récents dans la branche master
et les commits historiques dans la branche project-history/master
.
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
622e88e get history from blah blah blah
$ git log --oneline project-history/master
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Pour combiner ces deux branches, vous pouvez simplement lancer git replace
avec le commit que vous souhaitez remplacer suivi du commit qui remplacera.
Donc nous voulons remplacer fourth commit
dans la branche master
par fourth commit
de la branche project-history/master
:
$ git replace 81a708d c6e1e95
Maintenant, quand on regarde l’historique de la branche master
, il apparaît comme ceci :
$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit
Sympa, non ? Sans devoir changer tous les SHA-1 en amont, nous avons pu remplacer un commit dans notre historique avec un autre entièrement différent et tous les outils normaux (bisect
, blame
, etc) fonctionnent de manière transparente.
![replace5](png/replace5.png)
Ce qui est intéressant, c’est que fourth commit
a toujours un SHA-1 de 81a708d
, même s’il utilise en fait les données du commit c6e1e95
par lequel nous l’avons remplacé.
Même si vous lancez une commande comme cat-file
, il montrera les données remplacées :
$ git cat-file -p 81a708d
tree 7bc544cf438903b65ca9104a1e30345eee6c083d
parent 9c68fdceee073230f19ebb8b5e7fc71b479c0252
author Scott Chacon <schacon@gmail.com> 1268712581 -0700
committer Scott Chacon <schacon@gmail.com> 1268712581 -0700
fourth commit
Souvenez-vous que le parent réel de 81a708d
était notre commit de base (622e88e
) et non 9c68fdce
comme indiqué ici.
Une autre chose intéressante est que les données sont conservées dans nos références :
$ git for-each-ref
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/heads/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit refs/remotes/history/master
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/remotes/origin/HEAD
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit refs/remotes/origin/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit refs/replace/81a708dd0e167a3f691541c7a6463343bc457040
Ceci signifie qu’il est facile de partager notre remplacement avec d’autres personnes, puisque nous pouvons pousser ceci sur notre serveur et d’autres personnes pourront le télécharger. Ce n’est pas très utile dans le cas de la reconstruction d’historique que nous venons de voir (puisque tout le monde téléchargerait quand même les deux historiques, pourquoi alors les séparer ?), mais cela peut être utile dans d’autres circonstances.