Comment et pourquoi voler des arbres dans Git

des arbres


Dans cet article, je vais parler d'une astuce utile mais peu connue pour travailler avec git - comment créer facilement une validation à l'aide d'une arborescence à partir d'une autre validation. Autrement dit, comment obtenir l'état souhaité du projet sur n'importe quelle branche, si cet état a déjà été quelque part et quelque part dans le référentiel auparavant. Plusieurs exemples seront donnés sur la manière dont cela permet de résoudre avec élégance certains problèmes pratiques. Et en particulier, je vais parler d'une méthode que j'ai trouvée qui peut considérablement simplifier la correction de plusieurs conflits lors du rebase. De plus, cet article est un excellent moyen de comprendre dans la pratique ce qui constitue un commit in git.


Table des matières


La partie théorique. À propos des commits et des arbres
git commit-tree
Partie pratique
1. Synchronisation avec une autre branche
2. Comparaison de deux branches
3. Branche inversée
4. Inverse partiel
5. Fusion artificielle
6a. Méthode de rebase via la fusion - description
6b. Méthode de rebase via la fusion - script
7. Alias
Conclusion



La partie théorique. À propos des commits et des arbres


Commit est probablement le concept le plus basique de git, voyons en quoi il consiste. Chaque commit a son propre identifiant unique sous la forme d'un hachage, par exemple 5e45ecb . Et avec la commande suivante, connaissant le hachage, nous pouvons voir son contenu.


git cat-file -p 5e45ecb 

 tree 8640790949c12690fc71f9abadd7b57ec0539376 parent 930741d1f5fd2a78258aa1999bb4be897ba3d015 author Mark Tareshawty <tareby...@github.com> 1542718283 -0500 committer Mark Tareshawty <tareby...@github.com> 1542718283 -0500 gpgsig -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- Fix scoping so that we don't break the naming convention 

Ces quelques lignes représentent l'intégralité du contenu du commit:


  • arborescence - un lien vers un état de projet spécifique
  • parent - lien vers la validation parent
  • author - auteur du commit original + date
  • committer - créateur de ce commit + date
  • gpgsig - signature numérique (si disponible)
  • message - validation du texte

Permettez-moi de vous rappeler que la validation dans git (contrairement aux autres VCS) ne décrit pas les modifications apportées. C'est le contraire: chaque commit décrit l'état spécifique du projet dans son ensemble, et ce que nous considérons comme les modifications qu'il apporte est en fait une différence calculée dynamiquement par rapport à l'état précédent. Il est également intéressant de noter que tous les commits sont immuables (immuables), c'est-à-dire que, par exemple, avec rebase / cherry-pick / amend, des commits absolument nouveaux sont créés.


tree (tree) - en fait, c'est juste un dossier avec un contenu immuable spécifique. Un objet de type arborescence contient une liste de fichiers avec un contenu spécifique (blobs) et des sous-dossiers (arborescences). Et l'arborescence vers laquelle pointe chaque commit est le dossier racine du projet, ou plutôt son état spécifique.


afficher le contenu de l'arborescence

Cela peut être fait exactement de la même manière pour tout autre objet (commit / tree / blob), et il suffit de prendre les premiers caractères de hachage uniques: 8640790949c12690fc71f9abadd7b57ec0539376 -> 8640790.


 git cat-file -p 8640790 

 100644 blob 7ab08294a46f158c51460be3e7df6a190e15023b .env.example 100644 blob 0a1a4d1ad9ff3f35b67678ca893811e91b423af5 .gemset 040000 tree 033aa38ce0eab11fe229067c14ccce95e2b8b601 .github 100644 blob ca49bb7ffa6273b0be4ce7ba1accba456032fb11 .gitignore 100644 blob c99d2e7396e14ac072c63ec8419d9b8fede28d86 .rspec 100644 blob 65e77a2f59f635a8f24eb4714e8e43745c5c0eb9 .rubocop.yml 100644 blob 8e8299dcc068356889b365e23c948b92c6dfcd78 .ruby-version 100644 blob 19028f9885948aca2ba61f9d062e9dc21c21ad03 .stylelintrc.json 100644 blob 2f7a032fbc3f4f7195bfd91cb33889a684b572b9 .travis.yml 100644 blob 121615722a6c206a9fe24b9a1c9b647662a460d2 ARCHITECTURE.md 100644 blob 898195daeea0bbf8c5930deeaf1020ba8abab34a Gemfile 100644 blob de7ca707f9fe9172db941b65cdacaba7e024fc06 Gemfile.lock 100644 blob e6ff62fefd071b1a8ca279bae94ddbc4dd17b7a3 Gruntfile.js 100644 blob 0cac5b30fb32d36cce2aeb7d936be7b6207d68c7 MIT-LICENSE.txt 100644 blob c2c566e8cc3d440d3ee8041b79cded416db28136 Procfile 100644 blob d1fb2f575380e1e093a4d82e3f19e51f0b99a0a1 Procfile.dev 100644 blob 3a88e138f10fa65bd2cfe1a1d3292348205508b5 README.md 100644 blob 5366e6e073cc426518894cc379d3a07cf3c9cfb3 Rakefile 100644 blob e6d3d2d3e9d5122c5f75bbeee8ed0917ad38c131 app.json 040000 tree 94f83cf03bd6f1cf14672034877b14604744b7a2 app 040000 tree d4d859e82564250b4c4f2047de21e089e7555475 bin 100644 blob 1f71007621f17334fd6f2dd71c87b7a16867119c config.ru 040000 tree 9e8e4bf5ec44541aefff544672b94ca8a9d07bbf config 040000 tree 31b8d0e1fa2bb789dbd6319e04fc9f115952cf2a db 040000 tree 38e7a13e0e772c2a13e46d2007e239f679045bee doc 040000 tree a6e35ded8b35837660cf786e637912377f845515 lib 040000 tree d564d0bc3dd917926892c55e3706cc116d5b165e log 100644 blob 843523565ddee5e00f580d9c4e37fc2478fdaecc package-lock.json 100644 blob 791ee833ad316d75b1d2c83a64a3053fc952d254 package.json 040000 tree 4645317c52675d9889f89b26f4dd4d2ae1d8cbad public 040000 tree 31d3f8ae4a4ffe62787134642743ed32a35dbae2 resources 040000 tree 807ffa29868ef9c25ddb4b4126a4bb7f1b041bf0 script 040000 tree 4c3bf9a7f3679ba059b0f1c214a500d197546462 spec 040000 tree 136c8174412345531a9542cafef25ce558d2664f test 040000 tree e6524eafe066819e4181bc56c503320548d8009b vendor 

C'est en fait la caractéristique la plus importante du fonctionnement de git, l'identifiant de validation est vraiment un hachage de son contenu. Tout comme les hachages d'objets intégrés (arbres, taches).


Voyons maintenant ce qui se passe quand nous le faisons


 git commit -m "Fixed bug" 

Cette commande crée un nouveau commit qui capture les éléments suivants:


  • état du projet intermédiaire (enregistré en tant que nouvel objet d'arbre et son hachage pris)
  • lien vers la validation (parent) actuelle
  • auteur + committer + deux dates
  • valider le texte

Tout cela est enregistré, haché et un nouvel objet de validation est obtenu. Et l'équipe lève automatiquement le pointeur de branche actuel vers lui.


un peu de terminologie

Comme nous le savons déjà, l'arborescence est un objet qui contient l'état du projet à un certain moment dans le passé - lorsqu'un commit a été créé avec cette arborescence.


Le dossier de travail est appelé arbre de travail / copie de travail / répertoire de travail, ce qui est assez logique.


Nous avons également - zone / index de mise en scène - la zone des changements préparés. Mais logiquement, c'est aussi un arbre , ou plutôt, l'état qui est enregistré lors de la validation en tant qu'arbre. Par conséquent, il me semble qu'il serait plus logique d'appeler un arbre par étapes.



git commit-tree


Enfin, nous pouvons passer à la description de la commande git commit-tree dont nous avons besoin. Formellement, c'est l'une des commandes de bas niveau, elle est donc rarement mentionnée et utilisée. Nous ne considérerons pas les autres commandes de bas niveau qui lui sont associées (telles que git write-tree, git-update-index, elles sont également appelées commandes de plomberie). Nous ne sommes intéressés que par une conséquence particulière: avec cette commande, nous pouvons facilement copier (réutiliser) l'arbre d'état du projet à partir de n'importe quel autre commit.


Regardez son défi


 git commit-tree 4c835c2 -m "Fixed bug" -p a8fc5e3 

 d9aded78bf57ca906322e26883644f5f36cfdca5 

La commande git commit-tree valide également, mais de manière basique. Ici, vous devez spécifier explicitement l'arborescence (arborescence) 4c835c2 déjà existante et un lien vers le commit parent a8fc5e3. Et il renvoie le hachage du nouveau commit d9aded7, et la position de la branche ne change pas (donc, ce commit semble se figer dans l'air).



Partie pratique


Des exemples d'utilisation de cette commande sont illustrés dans le référentiel simple suivant.



Il contient trois branches:


maître - branche principale
alpha - la branche sur laquelle nous travaillons et sommes
beta - une branche qui était précédemment bloquée dans master


Toutes les actions sont faciles à répéter localement, pour cela il suffit de cloner le référentiel, de monter sur la branche alpha puis d'exécuter les commandes des exemples. Cet état initial est commun à tous les exemples.


 git clone https://github.com/capslocky/git-commit-tree-example.git cd ./git-commit-tree-example/ git checkout alpha 

sous les fenêtres

Toutes les commandes, y compris le script, fonctionnent également sous Windows. Vous avez juste besoin d'ouvrir le terminal bash dans le dossier du projet, par exemple, comme ceci


 "C:\Program Files\Git\git-bash.exe" --cd="D:\path\project" 


1. Synchronisation avec une autre branche


Défi:
Synchronisez l'état du projet sur la branche alpha avec la branche bêta . Autrement dit, vous devez créer un tel nouveau commit sur la branche alpha afin que l'état du projet devienne exactement le même que sur la branche bêta .


Plus précisément, une telle tâche est peu susceptible de se produire, mais c'est le cas le plus approprié pour démontrer l'approche.


La solution la plus simple consiste à prendre l'arborescence existante vers laquelle pointe la branche bêta et à la pointer du nouveau commit pour la branche alpha. Comme il s'agit du premier exemple, toute sa logique est considérée avec suffisamment de détails.


Tout d'abord, trouvez le hachage de validation pointé par la branche bêta:


 git rev-parse origin/beta 

 280c30ff81a574f8dd41721726cf60b22fb2eced 

280c30f - prenez simplement les premiers caractères


Trouvez maintenant le hachage de son arbre en affichant le contenu de la validation via git cat-file:


 git cat-file -p 280c30f 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows 

3c1afe7 - c'est l'arbre dont nous avons besoin


Et maintenant, nous allons créer un commit pointant vers cet arbre, et avec le commit parent nous indiquerons le commit actuel:


 git commit-tree 3c1afe7 -m "Synced with branch 'beta'" -p HEAD 

 eb804d403d4ec0dbeee36aa09da706052a7cc687 

Ça y est, le commit a été créé, l'équipe a eu son hachage. De plus, cette valeur sera toujours unique, car elle est calculée non seulement à partir de l'arbre, mais aussi à partir de l'auteur et de l'heure. Le commit lui-même est figé dans l'air, tant qu'il n'entre dans aucune des branches. Il nous suffit de prendre les premiers caractères: eb804d4 , cette valeur , unique pour chaque cas, je désignerai comme xxxxxxx . Regardons son contenu:


 git cat-file -p xxxxxxx 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 64fafc79e8f6d22f5226490daa5023062299fd6c author Peter <peter...@gmail.com> 1545230299 +0600 committer Peter <peter...@gmail.com> 1545230299 +0600 Synced with branch 'beta' 

Génial, il a la même arborescence que le commit sur la branche origine / beta. Et comme ce commit est un descendant direct de la branche courante, pour l'inclure dans la branche, il suffit de faire une fusion rapide


 git merge --ff xxxxxxx 

 Updating 64fafc7..xxxxxxx Fast-forward Azure.txt | 3 --- Bill.txt | 6 +----- Linus.txt | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) 

C'est fait. Maintenant, l'état du projet sur la branche alpha est exactement le même que sur la branche bêta. [mise à jour] Et si vous regardez ce que ce commit a changé après tout, nous verrons: il a inversé tous ses propres commit (changements) de la branche alpha et a ajouté tous les commit (changements) uniques de la branche beta, par rapport à leur commit ancêtre commun.




2. Comparaison de deux branches


Défi:
Comparez la branche alpha avec la branche bêta .


Le premier exemple montre que la validation créée affiche toutes les modifications qui sont la différence réelle entre les deux branches. Cette propriété facilite la comparaison d'une branche avec une autre. Il suffit de créer une troisième branche temporaire et d'y faire un commit similaire.


Donc, tout d'abord, ramenez la branche alpha à son état d'origine


 git reset --hard origin/alpha 

Créons une branche temporaire sur la branche actuelle et tenons-nous dessus


 git checkout -b temp 

Et il nous reste à faire la même chose que dans l'exemple précédent. Mais cette fois, nous rencontrerons une ligne. Pour ce faire, nous utilisons la syntaxe spéciale pour accéder à l' origine de l' arbre de validation / beta ^ {arbre} ou au même 280c30f ^ {arbre} .


 git merge --ff $(git commit-tree origin/beta^{tree} -m "Diff with branch 'beta'" -p HEAD) 

Terminé, essentiellement nous nous sommes matérialisés comme un différentiel de validation entre deux branches


 git show 

 git diff alpha origin/beta 

Bien sûr, nous pouvons créer un tel commit «comparatif» pour deux commits (états) dans le référentiel.




3. Branche inversée


Défi:
Annulez les derniers commits.


Revenons à la branche alpha et supprimons la branche temporaire


 git checkout alpha git branch -D temp 

Supposons que nous devons annuler les deux derniers commits sur la branche alpha. Il existe deux manières classiques de procéder:


  1. Exécutez git revert deux fois - par commit
  2. git reset, c.-à-d. réinitialiser la position de la branche

Mais vous pouvez le faire d'une troisième manière:


 git merge --ff $(git commit-tree 7a714bf^{tree} -m "Reverted to commit 7a714bf" -p HEAD) 

Cela ajoutera une nouvelle validation qui annule les modifications des deux validations précédentes. Contrairement à la première méthode, une seule validation est créée, même si vous devez annuler les dix dernières validations. Et la différence entre la méthode avec git reset est que nous ne lançons pas ces commits depuis la branche elle-même.


De plus, si vous devez ensuite retourner l'état d'origine de la branche, cela peut être fait de la même manière


 git merge --ff $(git commit-tree 64fafc7^{tree} -m "Reverted back to commit 64fafc7" -p HEAD) 

Dans le même temps, ces deux commits resteront dans l'histoire de la branche, selon laquelle on verra qu'elle a été annulée et retournée.




4. Inverse partiel


Défi:
Annulez les modifications apportées à certains fichiers au cours des dernières validations.


Encore une fois, ramenez la branche alpha à son état d'origine


 git reset --hard origin/alpha 

La branche alpha contient 3 validations, dans chacune desquelles des modifications sont apportées au fichier Bill.txt, dans la dernière validation, le fichier Azure.txt est également ajouté. Supposons que nous devions annuler les modifications apportées au fichier Bill.txt pour les 2 dernières validations, sans toucher à aucun autre fichier.


Tout d'abord, annulez tous les fichiers


 git merge --ff $(git commit-tree 7a714bf^{tree} -m "any text" -p HEAD) 

Ensuite, retournez la branche au commit précédent, mais sans toucher à l'état du projet sur le disque


 git reset HEAD~1 

Et maintenant, il suffit de zasteydit les fichiers nécessaires et de les valider, et d'autres modifications peuvent être ignorées.


 git add Bill.txt git commit -m "Reverted file Bill.txt to 7a714bf" git reset --hard HEAD 



5. Fusion artificielle


Défi:
Plongez une branche dans une autre pour obtenir un résultat prédéterminé.


Imaginez cette situation. Un bug critique a été détecté en production et, comme d'habitude, il doit être corrigé de toute urgence. Cependant, il n'est pas clair combien de temps il faudra pour l'étudier et créer le correctif correct, donc un correctif temporaire a été rapidement créé, qui a isolé l'interaction avec le module de problème. Ainsi, dans la branche master, un commit apparaît avec ce correctif temporaire, et après un certain temps au lieu de celui-ci dans master, vous devez écraser un correctif à part entière.


Par conséquent, nous devons fusionner la branche alpha en maître, mais cela ne devrait pas être une fusion traditionnelle, lorsque toutes les modifications uniques de la branche alpha sont ajoutées au maître par le haut et qu'un conflit se produit, et nous devons écraser complètement le maître avec la branche alpha.


Pour commencer, rappelons ce qu'est le commit de fusion - il s'agit en fait du même commit ordinaire, mais il n'a que deux commit parents, cela est clairement visible si vous regardez son contenu (la façon dont son arborescence est formée est un problème distinct) . Et qui est déterminé par qui est simple - le premier engagement parent est considéré comme le principal.


 git cat-file -p 7229df8 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master' 

Réinitialisez la branche alpha actuelle et passez en maître


 git reset --hard origin/alpha git checkout master 

Et maintenant, la même équipe, mais avec deux parents s'engage


 git merge --ff $(git commit-tree alpha^{tree} -m "Merge 'alpha' into 'master', but take 'alpha' tree" -p HEAD -p alpha) 

Terminé, nous avons mis en scène la branche alpha dans master, et nous n'avons pas eu à supprimer le code temporaire et à résoudre les conflits, car dans ce cas, nous devions simplement réécrire les dernières modifications.



En fait, il n'est pas si étrange de créer une fusion avec un arbre copié à partir d'un autre commit. De telles situations peuvent survenir parce que git est un outil très flexible qui vous permet de mettre en œuvre une variété d'approches pour travailler avec des branches et des référentiels. Mais encore, l'exemple le plus courant était dans notre référentiel depuis le tout début - essayez de l'analyser vous-même ou ouvrez un spoiler pour lire l'explication.


spoiler

Prenons attention à la façon dont la branche bêta a été étranglée en retour au maître. Pendant le temps où deux commits y figuraient, il n'y avait pas de nouveau commit dans la branche master elle-même. Cela signifie qu'avec la fusion bêta dans master, tous les conflits sont exclus en raison de modifications simultanées.




Si nous faisions fusionner la version bêta, une fusion rapide (comportement par défaut ) se produirait, c'est-à-dire que la branche principale se tiendrait sur le même commit que la branche bêta et qu'il n'y aurait pas de validation de fusion. Ce serait comme ça:



Mais ici, aucune fusion rapide n'a été effectuée à l'aide de la commande git merge beta --no-ff. Autrement dit, nous avons forcé la création du commit de fusion, même si cela n'était pas nécessaire. Et comme l'état final souhaité du projet pour la future fusion était connu - il s'agit d'un arbre bêta, git a simplement copié le lien vers cet arbre dans un nouveau commit:


 git cat-file -p origin/beta 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows 

 git cat-file -p 7229df8 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master' 


6a. Méthode de rebase via la fusion - description


Défi:
Il est nécessaire de créer une branche de rebase "lourde" (nombreux conflits sur différents commits).


Il existe un thème holivar classique dans git - rebase vs merge. Mais je ne vais pas holivarit. Au contraire, je parlerai de la manière de se faire des amis dans le cadre de cette tâche.


En général, git a été spécialement conçu pour que nous puissions effectivement fusionner. Et quand je suis arrivé au projet où le flux de travail est basé sur le rebase, j'étais d'abord mal à l'aise et inhabituel, jusqu'à ce que je développe des techniques qui simplifient mon travail quotidien avec git. L'un d'eux est ma méthode originale pour faire un rebase lourd.


Donc, nous devons rebaser la branche alpha lors du développement, afin que plus tard, elle soit aussi joliment colorée que la branche bêta. Si nous commençons le rebase comme d'habitude, le premier et le dernier commit produiront deux conflits différents à deux endroits différents. Mais si au lieu de rebaser nous venons de faire une fusion, il n'y aurait qu'un seul conflit en un seul endroit dans un seul commit de fusion.


Si vous voulez vous en assurer, je vous propose des équipes toutes faites sous le spoiler.


Texte masqué

Remettez les branches dans leur état d'origine


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Créer et se tenir debout sur la branche alpha-rebase-conflits et rebaser sur le maître


 git checkout -b alpha-rebase-conflicts git rebase master 

Il y aura des conflits à divers commits, y compris un conflit fantôme.


Essayons maintenant la fusion, revenons à la branche alpha et supprimons la branche pour le rebase.


 git checkout alpha git branch -D alpha-rebase-conflicts 

Passez au master et fusionnez


 git checkout master git merge alpha 

Il n'y aura qu'un seul conflit simple, nous le corrigeons et le faisons


 git add Bill.txt git commit -m "Merge branch 'alpha' into 'master'" 

Marge s'est terminée avec succès.


Les conflits Git font naturellement partie de nos vies, et cet exemple simple montre que la fusion est certainement plus pratique que le rebase à cet égard. Dans un projet réel, cette différence est mesurée par une quantité de temps et de nerfs beaucoup plus importante. Par conséquent, par exemple, il existe une recommandation ambiguë pour écraser toutes les validations d'une branche de fonctionnalité en une seule validation avant la fusion.


L'idée de cette méthode est de faire une fusion cachée temporaire dans laquelle nous allons résoudre tous les conflits à la fois. Rappelez-vous le résultat (arbre). Ensuite, exécutez le rebase habituel, mais avec l'option «résoudre automatiquement les conflits, choisir nos modifications». Et à la fin, ajoutez un commit supplémentaire à la branche, ce qui restaurera l'arborescence correcte.


Commençons. Encore une fois, ramenez les deux branches à leur état d'origine.


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Créons une temp de branche temporaire dans laquelle nous allons fusionner.


 git checkout -b temp git merge origin/master 

Le conflit.


Résolvons un conflit simple dans le fichier Bill.txt comme d'habitude (dans n'importe quel éditeur).
Notez qu'il n'y a qu'un seul conflit, et non deux, comme avec rebase.


 git add Bill.txt git commit -m "Merge branch 'origin/master' into 'temp'" 

Nous retournons à la branche alpha, effectuons un rebasage avec une résolution automatique de tous les conflits en notre faveur, et amenons la branche temporaire à l'état, et supprimons la branche temporaire elle-même.


 git checkout alpha git rebase origin/master -X theirs git merge --ff $(git commit-tree temp^{tree} -m "Fix after rebase" -p HEAD) git branch -D temp 


Enfin, magnifiquement mergim alpha en master.


 git checkout master git merge alpha --no-ff --no-edit 


Notez que master, alpha et la branche temporaire distante pointent tous les trois vers la même arborescence, bien qu'il s'agisse de trois validations différentes.


Inconvénients de cette méthode:


  • Il n'y a pas de correction manuelle de chaque validation de conflit - les conflits sont résolus automatiquement. Un tel commit intermédiaire peut ne pas être compilé.
  • Ajout (mais pas toujours) d'un commit supplémentaire à chaque rebase

Avantages:


  • Nous ne résolvons que les conflits réels (pas de conflits fantômes)
  • Tous les conflits sont résolus une seule fois.
  • Les deux premiers points font gagner du temps
  • Un historique complet des validations et de toutes les modifications est enregistré (par exemple, vous pouvez faire une sélection)
  • La méthode est implémentée sous la forme d'un script et peut toujours être utilisée pour rebaser si nécessaire (elle ne nécessite aucune connaissance sur les arbres, etc.)


6b. Méthode de rebase via la fusion - script


Le script est publié ici: https://github.com/capslocky/git-rebase-via-merge


Vérifions son travail sur notre exemple. Encore une fois, ramenez les deux branches à leur état d'origine


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Téléchargez le script et rendez-le exécutable


 curl -L https://git.io/rebase-via-merge -o ~/git-rebase-via-merge.sh chmod +x ~/git-rebase-via-merge.sh 

fenêtres

Le fichier apparaîtra ici: C: \ Users \ nom_utilisateur \ git-rebase-via-merge.sh


Modifiez la branche par défaut pour laquelle vous devez rebaser, dans notre cas, nous avons besoin d'origine / maître


 nano ~/git-rebase-via-merge.sh 

 default_base_branch='origin/master' 

Créons également une branche temporaire et restons debout pour ne pas toucher la branche alpha elle-même


 git checkout -b alpha-rebase-test 

Et maintenant, vous pouvez exécuter le script (au lieu de l'origine / master de git rebase traditionnel)


 ~/git-rebase-via-merge.sh 


résultat du script
 $ ~/git-rebase-via-merge.sh This script will perform rebase via merge. Current branch: alpha-rebase-test (64fafc7) Base branch: origin/master (9c6b60a) Continue (c) / Abort (a) c Auto-merging Bill.txt CONFLICT (content): Merge conflict in Bill.txt Automatic merge failed; fix conflicts and then commit the result. You have at least one merge conflict. Fix all conflicts in the following files, stage them up and type 'c': Bill.txt Continue (c) / Abort (a) c [detached HEAD 785d49e] Hidden temp commit to save result of merging 'origin/master' into 'alpha-rebase-test' as detached head. Merge succeeded on hidden commit: 785d49e Starting rebase automatically resolving any conflicts in favor of current branch. First, rewinding head to replay your work on top of it... Auto-merging Bill.txt [detached HEAD a680316] Added history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:45:50 2018 +0600 1 file changed, 6 insertions(+), 3 deletions(-) Committed: 0001 Added history of windows Auto-merging Bill.txt [detached HEAD dcd34a8] Replaced history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:55:42 2018 +0600 1 file changed, 4 insertions(+), 5 deletions(-) Committed: 0002 Replaced history of windows Auto-merging Bill.txt [detached HEAD 8d6d82c] Added file about Azure and info about Windows 10 Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 12:06:27 2018 +0600 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Azure.txt Committed: 0003 Added file about Azure and info about Windows 10 All done. Restoring project state from hidden merge with single additional commit. Updating 8d6d82c..268b320 Fast-forward Bill.txt | 4 ++++ 1 file changed, 4 insertions(+) Done. 


 ~/git-rebase-via-merge.sh origin/develop 

, ours / theirs :


ours — (HEAD)
theirs — (, origin/develop)


rebase — .



7.


git .


.


 git config alias.copy '!git merge --ff $(git commit-tree ${1}^{tree} -p HEAD -m "Tree copy from ${1}")' 

git copy xxx, xxx — .


 git copy xxx 


 git merge --ff $(git commit-tree xxx^{tree} -p HEAD -m "Tree copy from xxx") 


 git copy a8fc5e3 

 git copy origin/beta 

 git copy HEAD~3 

git amend.


 git commit --amend -m "Just for test" 

:


 git commit --amend 



, , . , . — . , , . . " " " " . ( , devops), , .

Source: https://habr.com/ru/post/fr433748/


All Articles