\begin{frame}[fragile]{Fusionner deux branches avec Git} \textit{Attention : avant de commencer, s'assurer que le répertoire est dans un état propre et qu'il n'y a pas de modifications non validées !} \medskip Git propose deux façons de fusionner deux branches : \begin{itemize} \item le \verb+merge+ : fusion \enquote{basique} de deux branches \\ \textbf{C'est l'alternative la plus simple} \item le \verb+rebase+ : modification plus avancée de l'historique \\ \textbf{Plus puissant mais plus dangereux} \end{itemize} \end{frame} \begin{frame}[fragile] \frametitle{Le merge} Le \verb+merge+ applique les modifications apportées depuis la divergence par la branche secondaire sur la branche de départ. \begin{figure}[h] \centering \input{src/tikz/merge.tex} \end{figure} Ici, C7 réalise le \verb+merge+ de la branche bleue dans la branche verte : les modifications apportées par C4 et C6 sont appliquées après C5. \medskip \Pause \begin{block}{Processus de fusion} \begin{enumerate} \item se déplacer sur la branche destination de la fusion \\ \verb+git checkout + \item lancer la fusion de la branche de travail \\ \verb+git merge + \end{enumerate} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le merge} \framesubtitle{Application} \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ echo nouvelle ligne >> API.txt && git commit -am "Commit sur master" \Pause [master 37d2273] Commit sur master 1 file changed, 1 insertion(+) \Pause $ git merge develop \Pause Merge made by the 'recursive' strategy. dev.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 dev.txt \Pause \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \frametitle{Le merge} \framesubtitle{Log !} \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ git log --graph --decorate \Pause * \textcolor{yellow}{commit 1892470146ed37358a45e8e5cd9715ec0fc3448a (}{\bf\textcolor{cyan}{HEAD -> }\textcolor{green}{master}}\textcolor{yellow}{)} \textcolor{red}{|}\textcolor{myGreen}{|} Merge: 37d2273 2292018 \textcolor{red}{|} \textcolor{myGreen}{|} Author: huetremy \textcolor{red}{|} \textcolor{myGreen}{|} Date: Mon Jan 14 14:50:00 2019 +0100 \textcolor{red}{|} \textcolor{myGreen}{|} \textcolor{red}{|} \textcolor{myGreen}{|} Merge branch 'develop' \textcolor{red}{|} \textcolor{myGreen}{|} \textcolor{red}{|} * \textcolor{yellow}{commit 2292018a27182fef507601140c7f93d679b93678 (}{\bf\textcolor{green}{develop}}\textcolor{yellow}{)} \textcolor{red}{|} \textcolor{myGreen}{|} Author: huetremy \textcolor{red}{|} \textcolor{myGreen}{|} Date: Mon Jan 14 14:01:37 2019 +0100 \textcolor{red}{|} \textcolor{myGreen}{|} \textcolor{red}{|} \textcolor{myGreen}{|} Ajout fichier dev \textcolor{red}{|} \textcolor{myGreen}{|} * \textcolor{myGreen}{|} \textcolor{yellow}{commit 37d2273def21ff6d8bb33f0600220764f67f2ab9} \textcolor{myGreen}{|}\textcolor{myGreen}{/} Author: huetremy \textcolor{myGreen}{|} Date: Mon Jan 14 14:49:12 2019 +0100 \textcolor{myGreen}{|} \textcolor{myGreen}{|} Commit sur master \textcolor{myGreen}{|} * \textcolor{yellow}{commit 168efba77dcfd59ba4346fe4a34427b71db75da7} \textcolor{myGreen}{|} Author: huetremy \textcolor{myGreen}{|} Date: Fri Jan 11 14:53:09 2019 +0100 \textcolor{myGreen}{|} \textcolor{myGreen}{|} Commit supplémentaire \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Avertissement} \begin{center} \includegraphics[height=3em]{./imgs/warning.jpg} \textbf{ATTENTION -- COMMANDE RISQUÉE} \end{center} Le \verb+rebase+ cause une \textbf{modification de l'historique} qui peut rendre l'état de votre arbre incohérent avec une éventuelle branche distante (GitLab\ldots). \bigskip \begin{block}{Conclusion} On rebase une branche locale mais \textbf{JAMAIS} une branche synchronisée \\ \tiny{(sauf si vous êtes absolument sûrs de ce que vous faites)}. \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Comparaison avec le merge} Le \verb+rebase+ intègre aussi les modifications d'une branche secondaire sur la branche cible depuis la divergence mais ne crée pas de commit de merge. \medskip Les commits effectués depuis la divergence sont \textbf{déplacés et réappliqués} après le dernier commit de la branche cible. \Pause \begin{figure}[h] \centering \input{src/tikz/avant_rebase.tex} \caption{Avant le rebase} \label{fig:avant_rebase} \end{figure} \begin{figure}[h] \centering \input{src/tikz/apres_rebase.tex} \caption{Après le rebase} \label{fig:apres_rebase} \end{figure} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Application simple} Après le rebase, pour ramener la branche de référence au bout de la chaîne de commits, on fait une fusion classique (merge). \begin{block}{Processus de rebase avec fusion} \begin{itemize} \item se déplacer sur la branche à rebase \\ \verb+git checkout + \item rebase la branche courante sur la branche de référence \\ \verb+git rebase + \item régler les éventuels conflits\ldots \item se déplacer sur la branche de référence \\ \verb+git checkout + \item fusionner la branche à rebase dans la branche de référence \\ \verb+git merge + \end{itemize} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Exemple} \begin{beamercolorbox}[rounded=true,shadow=true]{terminal} \begin{Verbatim} $ echo "Avant rebase" >> API.txt && git commit -am "Avant rebase" \Pause [master 6fe645e] Avant rebase 1 file changed, 1 insertion(+) \Pause $ git checkout develop && echo ''Ma première ligne'' >> dev.txt && git commit -am ''ajout à dev'' \Pause Basculement sur la branche 'develop' Votre branche est à jour avec 'origin/develop'. [develop 59eed37] ajout à dev 1 file changed, 1 insertion(+) \Pause $ git log --graph --decorate --all \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} * \textcolor{yellow}{commit 59eed37beb51329f95e90e6d6a6de85ca36c441a (}{\bf\textcolor{cyan}{HEAD -> }\textcolor{green}{develop}}\textcolor{yellow}{)} \textcolor{red}{|} Author: huetremy \textcolor{red}{|} Date: Mon Jan 14 15:33:59 2019 +0100 \textcolor{red}{|} \textcolor{red}{|} ajout à dev \textcolor{red}{|} \textcolor{red}{|} * \textcolor{yellow}{commit 6fe645e97ba1a69c99438fba05f21902d19f1055 (}{\bf\textcolor{green}{master}}\textcolor{yellow}{)} \textcolor{red}{|} \textcolor{myGreen}{|} Author: huetremy \textcolor{red}{|} \textcolor{myGreen}{|} Date: Mon Jan 14 15:31:47 2019 +0100 \textcolor{red}{|} \textcolor{myGreen}{|} \textcolor{red}{|} \textcolor{myGreen}{|} Avant rebase \textcolor{red}{|} \textcolor{myGreen}{|} \textcolor{red}{|} * \textcolor{yellow}{commit 1892470146ed37358a45e8e5cd9715ec0fc3448a} \textcolor{red}{|} \textcolor{yellow}{|}\textcolor{red}{|} Merge: 37d2273 2292018 \textcolor{red}{|} \textcolor{yellow}{|}\textcolor{red}{/} Author: huetremy \textcolor{red}{|}\textcolor{red}{/}\textcolor{yellow}{|} Date: Mon Jan 14 14:50:00 2019 +0100 \textcolor{red}{|} \textcolor{yellow}{|} \textcolor{red}{|} \textcolor{yellow}{|} Merge branch 'develop' \textcolor{red}{|} \textcolor{yellow}{|} * \textcolor{yellow}{|} \textcolor{yellow}{commit 2292018a27182fef507601140c7f93d679b93678} \textcolor{cyan}{|} \textcolor{yellow}{|} Author: huetremy \textcolor{cyan}{|} \textcolor{yellow}{|} Date: Mon Jan 14 14:01:37 2019 +0100 \textcolor{cyan}{|} \textcolor{yellow}{|} \textcolor{cyan}{|} \textcolor{yellow}{|} Ajout fichier dev \textcolor{cyan}{|} \textcolor{yellow}{|} \textcolor{cyan}{|} * \textcolor{yellow}{commit 37d2273def21ff6d8bb33f0600220764f67f2ab9} \textcolor{cyan}{|}\textcolor{cyan}{/} Author: huetremy \textcolor{cyan}{|} Date: Mon Jan 14 14:49:12 2019 +0100 \textcolor{cyan}{|} \textcolor{cyan}{|} Commit sur master \textcolor{cyan}{|} * \textcolor{yellow}{commit 168efba77dcfd59ba4346fe4a34427b71db75da7} [\ldots] \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ git rebase master \Pause Rembobinage préalable de head pour pouvoir rejouer votre travail par-dessus\ldots Application de ajout à dev \Pause $ git log --graph --decorate \Pause * \textcolor{yellow}{commit 1b9926f89453896c3f11e1f75b6871d70f35c5a4 (}{\bf\textcolor{cyan}{HEAD -> }\textcolor{green}{develop}}\textcolor{yellow}{)} \textcolor{red}{|} Author: huetremy \textcolor{red}{|} Date: Mon Jan 14 15:33:59 2019 +0100 \textcolor{red}{|} \textcolor{red}{|} ajout à dev \textcolor{red}{|} * \textcolor{yellow}{commit 6fe645e97ba1a69c99438fba05f21902d19f1055 (}{\bf\textcolor{green}{master}}\textcolor{yellow}{)} \textcolor{red}{|} Author: huetremy \textcolor{red}{|} Date: Mon Jan 14 15:31:47 2019 +0100 \textcolor{red}{|} \textcolor{red}{|} Avant rebase \textcolor{red}{|} * \textcolor{yellow}{commit 1892470146ed37358a45e8e5cd9715ec0fc3448a} \textcolor{myGreen}{|}\textcolor{yellow}{|} Merge: 37d2273 2292018 \textcolor{myGreen}{|} \textcolor{yellow}{|} Author: huetremy \textcolor{myGreen}{|} \textcolor{yellow}{|} Date: Mon Jan 14 14:50:00 2019 +0100 \textcolor{myGreen}{|} \textcolor{yellow}{|} \textcolor{myGreen}{|} \textcolor{yellow}{|} Merge branch 'develop' \textcolor{myGreen}{|} \textcolor{yellow}{|} \textcolor{myGreen}{|} * \textcolor{yellow}{commit 2292018a27182fef507601140c7f93d679b93678} \textcolor{myGreen}{|} \textcolor{yellow}{|} Author: huetremy \textcolor{myGreen}{|} \textcolor{yellow}{|} Date: Mon Jan 14 14:01:37 2019 +0100 \textcolor{myGreen}{|} \textcolor{yellow}{|} \textcolor{myGreen}{|} \textcolor{yellow}{|} Ajout fichier dev \textcolor{myGreen}{|} \textcolor{yellow}{|} * \textcolor{yellow}{|} commit 37d2273def21ff6d8bb33f0600220764f67f2ab9 \textcolor{yellow}{|}\textcolor{yellow}{/} Author: huetremy \textcolor{yellow}{|} Date: Mon Jan 14 14:49:12 2019 +0100 [\ldots] \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Principe} Cet outil puissant permet de ré-écrire comme bon vous semble votre historique \textbf{local}. \medskip {\tiny On ne le répètera jamais assez : \textbf{n'utilisez jamais cette commande sur des commits déjà poussés, sauf si vous savez exactement ce que vous faites et connaissez les conséquences.}\par} \Pause \begin{block}{Cas d'utilisation} \begin{itemize} \item Changer l'ordre des commits \item Fusionner des commits \item Supprimer des commits \item Modifier le contenu d'un ou plusieurs commits \item \ldots \end{itemize} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Fonctionnement} Les commits que vous souhaitez modifier ou ré-ordonner vous sont présentés dans un éditeur. Pour chaque commit, vous pouvez choisir une action. \medskip \Pause \begin{block}{Principales commandes pour le rebase interactif} \begin{itemize} \item \texttt{pick} : garder le commit en l'état \Pause \item \texttt{reword} : éditer le message de commit \Pause \item \texttt{edit} : modifier le contenu du commit \Pause \item \texttt{squash} : fusionner avec le commit précédent \Pause \item \texttt{drop} : supprimer le commit \end{itemize} \end{block} \medskip \Pause Il est aussi possible de changer l'ordre des commits en les ordonnançant manuellement. \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Exemple (1/4)} Vous avez développé une fonctionnalité, puis commencé une deuxième sans être certain de la garder en l'état, puis réparé la première.\Pause \medskip \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ echo "Ajout d'une super fonctionnalité" >> F1.txt $ git add F1.txt && git commit -m "Nouvelle fonctionnalité : F1" [master b191156] Nouvelle fonctionnalité : F1 1 file changed, 1 insertion(+)\Pause $ echo "Début d'une autre fonctionnalité" >> F2.txt $ git add F2.txt && git commit -m "wip F2" [master dc4eba5] wip F2 1 file changed, 1 insertion(+)\Pause $ echo "Rajout du point virgule manquant\ldots" >> F1.txt $ git commit -am "Résolution de bug sur F1" [master a1b72f7] Résolution de bug sur F1 1 file changed, 1 insertion(+), 1 deletion(-)\Pause \end{Verbatim} \end{beamercolorbox} \medskip Vous voulez maintenant pousser un historique propre pour faciliter la compréhension des autres contributeurs. \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Exemple (2/4)} L'historique local est dans l'état suivant : \medskip \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ git log --oneline \textcolor{yellow}{a1b72f7 (}\textcolor{cyan}{HEAD ->} \textcolor{green}{master}\textcolor{yellow}{)} Résolution de bug sur F1 \textcolor{yellow}{dc4eba5} wip F2 \textcolor{yellow}{b191156} Nouvelle fonctionnalité : F1 [\ldots] \end{Verbatim} \end{beamercolorbox} \medskip \Pause \begin{block}{Objectifs} \begin{itemize} \item \textbf{Fusionner} les commits concernant F1 (le bug est trop minime pour en faire un commit\ldots) \item \textbf{Renommer} le commit concernant F2 (finalement, vous gardez votre développement en l'état). \end{itemize} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Exemple (3/4)} On lance la commande de rebase, et on arrive dans un éditeur avec le contenu suivant. {\tiny Les commits les plus anciens sont en haut, contrairement aux logs} \medskip \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ git rebase -i HEAD~3 \textcolor{yellow}{pick} b191156 Nouvelle fonctionnalité : F1 \textcolor{yellow}{pick} dc4eba5 wip F2 \textcolor{yellow}{pick} a1b72f7 Résolution de bug sur F1 \end{Verbatim} \end{beamercolorbox} \medskip\Pause On change l'ordre des commits ainsi que les commandes, puis on quitte l'éditeur. \medskip \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} \textcolor{yellow}{pick} b191156 Nouvelle fonctionnalité : F1 \textcolor{yellow}{squash} a1b72f7 Résolution de bug sur F1 \textcolor{yellow}{reword} dc4eba5 wip F2 \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Exemple (4/4)} Il nous faudra encore renseigner les nouveaux messages de commits pour la fusion et le renommage. Une fois validés, Git joue les \textbf{nouveaux} commits un à un, comme pour un rebase classique. \medskip\Pause \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} [detached HEAD c76ff8d] Nouvelle fonctionnalité : F1 Date: Wed Jan 16 01:24:52 2019 +0100 1 file changed, 2 insertions(+) create mode 100644 F1.txt [detached HEAD db9f68a] Début de la fonctionnalité F2 1 file changed, 1 insertion(+) create mode 100644 F2.txt Successfully rebased and updated refs/heads/master. $ git log --oneline \textcolor{yellow}{db9f68a (}\textcolor{cyan}{HEAD -> }\textcolor{green}{master}\textcolor{yellow}{)} Début de la fonctionnalité F2 \textcolor{yellow}{c76ff8d} Nouvelle fonctionnalité : F1 [\ldots] \end{Verbatim} \end{beamercolorbox}\Pause \end{frame} \begin{frame}[fragile] \frametitle{Le rebase} \framesubtitle{Rebase interactif -- Conclusion} Il y a beaucoup d'autres commandes : édition de commit, création de commits de fusion, exécution de commande shell\ldots~À adapter au besoin. \medskip\Pause \begin{block}{Soyez toujours prudents !} Par exemple, lorsque vous changez l'ordre de commits qui modifient le même fichier. Vous risquez de vous retrouver avec des \textbf{conflits en cascade} complexes à résoudre. En cas de problèmes, utilisez la commande \verb+git rebase --abort+ pour revenir en arrière, et ré-étudiez le problème. \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le cherry-pick} \framesubtitle{Ou comment récupérer des commits \og{}à la demande\fg{}} Applique les changements introduits par un ou plusieurs commits. Il faut éviter d'utiliser cette commande à tort et à travers, mais elle est très utile dans certains cas bien spécifiques.\Pause \medskip {\tiny Contrairement au rebase, on peut cherry-pick des commits déjà poussés.}\Pause \medskip \begin{block}{Cas d'utilisation} \begin{itemize} \item Récupérer une fonctionnalité d'une branche sans le reste \item Rétropropager la correction d'un bug faite sur une nouvelle branche \item \ldots \end{itemize} \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le cherry-pick} \framesubtitle{Exemple (1/2)} Je règle un bug sur une branche \texttt{develop}, et je continue à développer. Je veux que la résolution soit portée sur \texttt{master}, mais sans récupérer les fonctionnalités instables de \texttt{develop}. \medskip {\tiny On verra plus tard comment éviter cette situation pas très propre\ldots.}\Pause \begin{figure}[h] \centering \input{src/tikz/cherry-pick.tex} \end{figure}\Pause \begin{block}{} Comment récupérer uniquement \texttt{C4} ? \end{block} \end{frame} \begin{frame}[fragile] \frametitle{Le cherry-pick} \framesubtitle{Exemple (2/2)} \begin{beamercolorbox}[rounded=true, shadow=true]{terminal} \begin{Verbatim} $ git checkout -b develop\Pause $ cat dev.txt $ echo "Resolution de bug" >> dev.txt $ git commit -am "Resolution de bug" [develop \textcolor{yellow}{c586d4d}] Resolution de bug 1 file changed, 1 insertion(+)\Pause $ echo "Debut nouvelle fonctionnalité" >> dev.txt $ git commit -am "Nouvelle fonctionnalité" [develop \textcolor{yellow}{2bbe0bd}] Nouvelle fonctionnalité 1 file changed, 1 insertion(+) $ cat dev.txt Resolution de bug Debut nouvelle fonctionnalité\Pause $ git checkout master Switched to branch 'master' Your branch is up to date with 'origin/master'.\Pause $ git show HEAD --oneline \textcolor{yellow}{db9f68a (}\textcolor{cyan}{HEAD ->} \textcolor{green}{master}\textcolor{yellow}{)} Début de la fonctionnalité F2\Pause $ git cherry-pick -x c586d4d [master 6bc2b57] Resolution de bug 1 file changed, 1 insertion(+)\Pause $ git show HEAD --oneline \textcolor{yellow}{6bc2b57 (}\textcolor{cyan}{HEAD ->} \textcolor{green}{master}\textcolor{yellow}{)} Resolution de bug (cherry picked from commit \textcolor{yellow}{c586d4d})\Pause $ cat dev.txt Resolution de bug \end{Verbatim} \end{beamercolorbox} \end{frame} \begin{frame}[fragile] \frametitle{Le cherry-pick} \framesubtitle{Conclusion} \begin{block}{Recommandations} \begin{itemize} \item Préférer le merge au cherry-pick quand c'est possible\Pause \item Le cherry-pick n'évite pas les conflits, par exemple si un fichier a été modifié sur les deux branches depuis le commit ancêtre commun\Pause \item Toujours utiliser le flag \texttt{-x} pour retrouver le commit de référence\Pause \item Utiliser le flag \texttt{-e} pour modifier le message de commit\Pause \end{itemize} \end{block} \end{frame}