Skip to content

Create a patch

Time to read:Activity duration:
6 minutes10 minutes

Overview

The diff command can be used to generate a patch output for uncommited files.

bash
git diff [ --cached ] [ {FILE}… ]  > {PATCH_FILE}

When files are already committed, you can use the Git format-patch command:

bash
git format-patch -1 HEAD

Activity goal

In this section, you will use both diff and format-patch commands to generate shareable patch files.

You will see how this can be done in two contexts:

  1. with local changes that are not even staged;
  2. from staged changes, a scenario that could be more useful when you want a limited patch while having a lot of local changes.
  3. from commit content, something useful to share you local work before you open a pull-request, or to retrofit them on another branch.

Setup

Use the utility script to create the playground folder:

bash
./scripts/create-playground.sh patch_create

This script prepare a working directory where you have both come commit on a simple project and updated files that are not staged.

Create a patch from unstaged changes

This use case simulates a scenario where you are doing pair programming with a teamate. You both implement part of a feature and now it's time to share them as a patch to your teamate, so they can handle the commit on their side.

Go to the playground folder:

bash
cd playgrounds/patch_create

You can verify that there's pending changes ready to be commit:

bash
git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   index.html
        modified:   src/main.ts
        modified:   src/style.css

no changes added to commit (use "git add" and/or "git commit -a")

Now save it as a patch:

bash
git diff > my-side-of-the-work.patch

Check the content of the patch file:

bash
less my-side-of-the-work.patch
diff
diff --git a/index.html b/index.html
index ae67761..63d2549 100644
--- a/index.html
+++ b/index.html
@@ -17,9 +17,9 @@
       </div>

       <div id="game-area">
-        <div class="tower-peg" style="left: calc(16.666% - 5px)"></div>
-        <div class="tower-peg" style="left: calc(50% - 5px)"></div>
-        <div class="tower-peg" style="left: calc(83.333% - 5px)"></div>
+        <div class="tower-peg" style="left: 16.666%"></div>
+        <div class="tower-peg" style="left: 50%"></div>
+        <div class="tower-peg" style="left: 83.333%"></div>
         <div class="tower-base"></div>
       </div>

diff --git a/src/main.ts b/src/main.ts
index 034a325..38b5075 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -4,8 +4,6 @@ import "./style.css";
 const DISK_HEIGHT = 28;
 const DISK_GAP = 2;
 const BASE_HEIGHT = 14;
-const MIN_DISK_PCT = 10;
-const MAX_DISK_PCT = 28;
 const ANIMATION_DELAY = 420;

 const state = new GameState();
@@ -19,11 +17,6 @@ const gameArea = document.getElementById("game-area") as HTMLDivElement;

 let animationTimer: ReturnType<typeof setInterval> | null = null;

-function getDiskWidthPct(size: number, total: number): number {
-  if (total <= 1) return MAX_DISK_PCT;
-  return MIN_DISK_PCT + ((size - 1) / (total - 1)) * (MAX_DISK_PCT - MIN_DISK_PCT);
-}
-
 function getDiskColor(size: number, total: number): string {
   const hue = ((size - 1) / (total - 1)) * 200 + 10;
   return `hsl(${hue}, 75%, 55%)`;
@@ -35,13 +28,14 @@ function createDisks(total: number): void {
   }
   diskElements.clear();

+  gameArea.style.setProperty("--n", String(total));
+
   for (let size = 1; size <= total; size++) {
     const disk = document.createElement("div");
     disk.className = "disk";
     disk.dataset.size = String(size);

-    const widthPct = getDiskWidthPct(size, total);
-    disk.style.width = `${widthPct}%`;
+    disk.style.setProperty("--i", String(size));
     disk.style.height = `${DISK_HEIGHT}px`;
     disk.style.backgroundColor = getDiskColor(size, total);

@@ -58,7 +52,9 @@ function removeDisks(): void {
 }

 function render(): void {
+  const areaWidth = gameArea.clientWidth;
   const areaHeight = gameArea.clientHeight;
+
   const pegBottom = BASE_HEIGHT;

   for (const [size, el] of diskElements) {
@@ -67,17 +63,18 @@ function render(): void {
     for (let t = 0; t < 3; t++) {
       const pos = state.towers[t].indexOf(size);
       if (pos !== -1) {
-        const diskWidthPct = getDiskWidthPct(size, state.totalDisks);
-        const leftPct = ((t + 0.5) / 3) * 100 - diskWidthPct / 2;
-        const diskBottom = pegBottom + pos * (DISK_HEIGHT + DISK_GAP);
+        const towerCenterX = (areaWidth * (t + 0.5)) / 3;
+        const diskWidth = el.offsetWidth;
+        const diskVisualHeight = DISK_HEIGHT;
+        const diskBottom = pegBottom + pos * (diskVisualHeight + DISK_GAP);

-        if (diskBottom + DISK_HEIGHT > areaHeight) {
+        if (diskBottom + diskVisualHeight > areaHeight) {
           el.style.display = "none";
           found = true;
           break;
         }

-        el.style.left = `${leftPct}%`;
+        el.style.left = `${towerCenterX - diskWidth / 2}px`;
         el.style.bottom = `${diskBottom}px`;
         el.style.display = "";
         found = true;
diff --git a/src/style.css b/src/style.css
index c43d5ed..eed36c3 100644
--- a/src/style.css
+++ b/src/style.css
@@ -161,4 +161,6 @@ button:disabled {
   z-index: 1;
   box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3);
   will-change: left, bottom;
+  --ratio: calc((var(--i) - 1) / (var(--n) - 1));
+  width: calc(4% + var(--ratio) * 24%);
 }

This is it, you can check this patch file contains all the changes that needs to be commit to the repository.

But how can you proceed if you need to share more than a simple change? How can you share a list of commits that you performed on the repository?

This is what we are going to see in the section section bellow.

Create a patch from staged changes

In this setup you have three local modification.

But in the case you want to share only the changes applied on index.html, how can it be done?

Just stage the changes you want in your patch:

bash
git add index.html

Now you have:

  • 1 staged change for index.html ;
  • 2 unstaged changes for the TypeScript and CSS sources.

Create a patch from staged content:

bash
git diff --cached > html-fixes.patch
diff
diff --git a/index.html b/index.html
index ae67761..63d2549 100644
--- a/index.html
+++ b/index.html
@@ -17,9 +17,9 @@
       </div>

       <div id="game-area">
-        <div class="tower-peg" style="left: calc(16.666% - 5px)"></div>
-        <div class="tower-peg" style="left: calc(50% - 5px)"></div>
-        <div class="tower-peg" style="left: calc(83.333% - 5px)"></div>
+        <div class="tower-peg" style="left: 16.666%"></div>
+        <div class="tower-peg" style="left: 50%"></div>
+        <div class="tower-peg" style="left: 83.333%"></div>
         <div class="tower-base"></div>
       </div>

If you check the output, you can see that your patch file only include changes for the index.html file, as expected.

Create a patch from a commit

There's multiple use case where you might want to generate a patch from existing commits.

  1. You just made a commit and you need to share to coworkers before opening a formal pull-request.
  2. You are working on a large feature and some shared work is already in few commits hidden in your local history.
  3. You worked on full set of features and you wan to move your changes to a new branch

In this section I will only detail the most common scenario and I will give you a quick glipse on how you can handle the two other use cases.

First, let's commit the pending changes:

  1. Stage changes:
    bash
    git add index.html src/main.ts src/style.css
  2. An commit:
    bash
    git commit -m 'fix: align tower pegs with disk center positions'

You will now use the format-patch Git command to generate a patch file for this commit:

bash
git format-patch HEAD~1

You should be more familiar with Git syntax from now. HEAD~1 reference 1 commit from current HEAD content, so this is you last commit

This command will generate a patch file 0001-fix-align-tower-pegs-with-disk-center-positions.patch.

  • 0001 is the commit order
  • what follows is build from your commit message.
  • .patch is the usual file extension for a patch and would be hard to be more explicit.

This path file is structured with email-style headers (author, date, message):

console
From d81ea11b280afe9c9d42f790981d1326e812b9b8 Mon Sep 17 00:00:00 2001
From: Sylvain Gamel <code@sylvaingamel.fr>
Date: Tue, 11 Aug 2026 09:58:42 +0200
Subject: [PATCH] fix: align tower pegs with disk center positions

---
 index.html    |  6 +++---
 src/main.ts   | 25 +++++++++++--------------

This is by design as email can be a very effective way to share code changes. Some projects, like the Linux kernel, are still operating this way.

For the two other patch use case, you will use the very same format-path command, with a small difference in the way you refer to changes:

  • HEAD~i build a patch for last i commits, this is the use case we just explored.
  • <PARENT_HASH>^..<TARGET_HASH> build a patch from PARENT_HASH to TARGET_HASH (both included).
  • <START_BRANCH>..<FEATURE_BRANCH> build a patch for all commits in FEATURE_BRANCH created from MAIN_BRANCH. For example main..feature_branch

I let you experiment with these two extra use cases, but they should be more marginal in your daily workflow.

What we learned

You know how to create a patch file from a serie of changes:

  • git diff captures unstaged changes.
  • git diff --cached captures staged changes.
  • git format-patch generates email-ready patches from commits with full metadata.

Patch files are plain text and can be inspected or shared. Git supports email sharing out-of-the-box. You can explore Git commands dedicated to email workflow like send-email or imap-send.