It takes all the changes introduced by branch featureB (since the merge-base with your current branch) and applies them to your working tree/index as one combined change, without creating a merge commit and without recording the branch history.
After running it:
- the changes are staged (like a big “combined” diff)
- you still need to run
git commit to create the single squashed commit - it does not mark
featureB as “merged” in Git history (a later normal merge may try to reapply commits).
\begin{tikzpicture}[
commit/.style={circle, draw=black, fill=blue!20, minimum size=10mm, font=\small\ttfamily},
branch/.style={rectangle, rounded corners, draw=green!60!black, fill=green!10, minimum width=15mm, minimum height=6mm, font=\small\ttfamily},
staged/.style={rectangle, draw=orange!80!black, fill=orange!15, minimum width=30mm, minimum height=15mm, font=\small},
arrow/.style={-Stealth, thick},
label/.style={font=\small},
]
% Title
\node[font=\Large\bfseries, text=blue!50!black] at (6, 11) {\texttt{git merge –squash featureB}};
% ======== BEFORE (top) ========
\node[font=\large\bfseries, anchor=west] at (0, 10) {1. Before:};
% Main branch commits
\node[commit] (C1) at (1, 8) {C1};
\node[commit] (C2) at (2.5, 8) {C2};
% FeatureB commits
\node[commit] (F1) at (2.5, 6.5) {F1};
\node[commit] (F2) at (4, 6.5) {F2};
\node[commit] (F3) at (5.5, 6.5) {F3};
% Arrows
\draw[arrow] (C1) – (C2);
\draw[arrow] (C2) – (F1);
\draw[arrow] (F1) – (F2);
\draw[arrow] (F2) – (F3);
% Branch labels
\node[branch, above=2mm of C2] {main};
\node[branch, fill=purple!10, draw=purple!60!black, below=2mm of F3] {featureB};
% HEAD pointer (on main branch)
\node[label, text=red, font=\small\bfseries, below=1mm of C2] {HEAD → main};
% ======== AFTER SQUASH (middle) ========
\node[font=\large\bfseries, anchor=west] at (0, 5) {2. After \texttt{git merge –squash}:};
% Working tree/index
\node[staged, minimum width=40mm, minimum height=18mm] (staged) at (3.5, 2.5) {};
\node[font=\small\bfseries, text=orange!80!black, anchor=south] at (staged.north) {Working Tree/Index};
\node[font=\footnotesize, align=center] at (staged.center) {All changes from\\F1 + F2 + F3\\(STAGED)};
\node[font=\footnotesize, text=gray, below=1mm of staged] {Need to run \texttt{git commit}};
\node[font=\footnotesize, text=red, below=6mm of staged] {(still on main branch)};
% Arrow from before to after squash
\draw[-Stealth, ultra thick, blue!60!black, dashed] (F3) to[out=-45, in=90] node[right, font=\small] {squash} (staged.north);
% ======== AFTER COMMIT (bottom) ========
\node[font=\large\bfseries, anchor=west] at (8, 10) {3. After \texttt{git commit}:};
% Main branch commits
\node[commit] (C1b) at (9, 8) {C1};
\node[commit] (C2b) at (10.5, 8) {C2};
\node[commit, fill=green!30] (C3) at (12, 8) {C3};
% FeatureB commits (still exist but not merged)
\node[commit, opacity=0.3] (F1b) at (10.5, 6.5) {F1};
\node[commit, opacity=0.3] (F2b) at (12, 6.5) {F2};
\node[commit, opacity=0.3] (F3b) at (13.5, 6.5) {F3};
% Arrows
\draw[arrow] (C1b) – (C2b);
\draw[arrow] (C2b) – (C3);
\draw[arrow, opacity=0.3] (C2b) – (F1b);
\draw[arrow, opacity=0.3] (F1b) – (F2b);
\draw[arrow, opacity=0.3] (F2b) – (F3b);
% Branch labels
\node[branch, above=2mm of C3] {main};
\node[branch, fill=purple!10, draw=purple!60!black, opacity=0.3, below=2mm of F3b] {featureB};
% HEAD pointer (moved to C3 on main)
\node[label, text=red, font=\small\bfseries, below=0mm of C3] {HEAD → main};
% Annotations
\node[font=\footnotesize, align=center, text=green!50!black, above=7mm of C3] {Single squashed commit};
\node[font=\footnotesize, align=center, text=gray, below=8mm of F2b] {featureB NOT merged\∈ Git history};
% ======== Key notes at bottom ========
\node[font=\normalsize, align=left, text=blue!60!black] at (6.5, 0) {%
\textbf{Key Points:} All F1+F2+F3 changes → one commit (C3) • No merge commit • featureB history not recorded};
\end{tikzpicture}