Skip to content

Commit c6155b9

Browse files
committed
docs: expand patching how-to into a mature guide
Add a Prerequisites section explaining that dfetch diff needs a committed upstream baseline before edits are made. Add an "Upgrading the upstream version" section with three explicit outcome paths: clean apply, fuzz-apply (refresh patch), and conflict (manual resolution + update-patch). Add a Troubleshooting section covering the five most common failure messages users encounter with patches. Expand the manifest wiring section to cover patch file organisation conventions and the behaviour of update-patch with multiple patches (always updates the last entry). Expand the format-patch section to document the --output-directory flag. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DsDq9BdiWvfxtL9HMvtmaa
1 parent 9aea63f commit c6155b9

1 file changed

Lines changed: 164 additions & 18 deletions

File tree

doc/howto/patching.rst

Lines changed: 164 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,32 @@ The full lifecycle looks like this:
2222
1. :ref:`patching-create` — capture local edits as a ``.patch`` file with ``dfetch diff``
2323
2. :ref:`patching-wire` — reference the patch from the manifest so it is applied on every fetch
2424
3. :ref:`patching-update` — refresh the patch as your edits evolve with ``dfetch update-patch``
25-
4. :ref:`patching-upstream` — reformat the patch for upstream use with ``dfetch format-patch``
25+
4. :ref:`patching-upstream-bump` — re-apply your patch when you move to a new upstream version
26+
5. :ref:`patching-upstream` — reformat the patch for upstream use with ``dfetch format-patch``
27+
28+
.. _patching-prereq:
29+
30+
Before you begin
31+
----------------
32+
33+
*Dfetch* calculates the diff for a project by comparing the working tree
34+
against the revision recorded in the project's ``.dfetch_data.yaml`` metadata
35+
file. For that comparison to be meaningful, the fetched files should already
36+
be committed to your superproject's VCS — they become the baseline that the
37+
patch is measured against.
38+
39+
After fetching, commit before editing:
40+
41+
.. code-block:: console
42+
43+
$ dfetch update some-project
44+
$ git add some-project/
45+
$ git commit -m "vendor: add some-project v1.2.3"
46+
47+
You can then make edits to ``some-project/`` and capture them with
48+
``dfetch diff``. Both committed and uncommitted edits are included in the
49+
generated patch, so you do not need to commit every intermediate step — only
50+
the clean upstream baseline matters.
2651

2752
.. _patching-create:
2853

@@ -43,6 +68,13 @@ metadata file and writes a patch file named ``some-project.patch`` (or
4368

4469
.. asciinema:: ../asciicasts/diff.cast
4570

71+
**What goes into the patch**
72+
73+
The diff captures all tracked modifications and any new untracked files in the
74+
vendored directory. Files ignored by your superproject's VCS (via
75+
``.gitignore`` or ``svn:ignore``) and the ``dfetch`` metadata file itself are
76+
always excluded.
77+
4678
**Controlling which revisions are compared**
4779

4880
By default, *Dfetch* uses the revision stored in the project's metadata as the
@@ -68,8 +100,8 @@ See :ref:`diff` in the command reference for all options.
68100
Adding the patch to the manifest
69101
---------------------------------
70102

71-
Once you have a patch file, reference it from the project entry in
72-
``dfetch.yaml`` using the :ref:`patch` attribute:
103+
Once you have a patch file, commit it to your repository and reference it from
104+
the project entry in ``dfetch.yaml`` using the :ref:`patch` attribute:
73105

74106
.. code-block:: yaml
75107
@@ -82,7 +114,23 @@ Once you have a patch file, reference it from the project entry in
82114
patch: some-project.patch
83115
84116
From this point on, every ``dfetch update`` will fetch the upstream source and
85-
re-apply the patch on top.
117+
re-apply the patch on top. You can test the round-trip immediately:
118+
119+
.. code-block:: console
120+
121+
$ dfetch update --force some-project
122+
123+
The ``--force`` flag overwrites the working tree with the freshly fetched and
124+
patched version. Confirm the result looks right, then commit the manifest
125+
change and the patch file together.
126+
127+
**Organizing patch files**
128+
129+
Keep patch files alongside ``dfetch.yaml`` or in a dedicated subdirectory such
130+
as ``patches/``. *Dfetch* resolves patch paths relative to the manifest file,
131+
so as long as the path in the manifest matches the location on disk you have
132+
full flexibility. Committing the patch files to VCS ensures every team member
133+
and every CI run gets the same result.
86134

87135
**Multiple patches**
88136

@@ -97,7 +145,9 @@ order:
97145
98146
Patches are applied in the order listed. A good convention is to prefix each
99147
file name with a zero-padded number so they sort correctly and their purpose is
100-
clear at a glance.
148+
clear at a glance. The ``dfetch update-patch`` command always updates the
149+
**last** patch in the list, so the earlier patches represent stable, settled
150+
changes and the final one accumulates ongoing work.
101151

102152
See :ref:`patch` in the manifest reference for the full attribute syntax.
103153

@@ -106,22 +156,29 @@ See :ref:`patch` in the manifest reference for the full attribute syntax.
106156
Refreshing a patch
107157
------------------
108158

109-
As your local edits evolve — or when the upstream version changes — the
110-
existing patch file may no longer apply cleanly. Instead of manually
111-
regenerating it, run:
159+
As your local edits evolve, the existing patch file may become stale. Instead
160+
of manually regenerating it, run:
112161

113162
.. code-block:: console
114163
115164
$ dfetch update-patch some-project
116165
117-
This regenerates the last patch for ``some-project`` from the current working
118-
tree, keeping the upstream revision unchanged. It is safe to run repeatedly
119-
as you iterate on the fix.
166+
This command:
120167

121-
When the upstream version changes, *Dfetch* applies patches with fuzzy
122-
matching, so a patch can survive minor context changes without needing an
123-
immediate refresh. If the patch no longer applies at all, ``dfetch update``
124-
will report the failure and you can refresh with ``dfetch update-patch``.
168+
1. Re-fetches the upstream revision (without applying any patches).
169+
2. Computes the diff between that clean baseline and your current working tree.
170+
3. Overwrites the **last** patch in the manifest list with the new diff.
171+
4. Re-fetches the project and applies all patches so the working tree is left
172+
in the patched state.
173+
174+
It is safe to run repeatedly as you iterate on a fix. The upstream revision
175+
stays unchanged — only the patch file is updated.
176+
177+
.. note::
178+
179+
``update-patch`` requires the project directory to have **no uncommitted
180+
changes** in the superproject. Commit or stash your work first, then run
181+
the command.
125182

126183
.. asciinema:: ../asciicasts/update-patch.cast
127184

@@ -137,6 +194,52 @@ See :ref:`update-patch` in the command reference for all options.
137194

138195
.. scenario-include:: ../features/update-patch-in-svn.feature
139196

197+
.. _patching-upstream-bump:
198+
199+
Upgrading the upstream version
200+
-------------------------------
201+
202+
When you want to move to a new upstream release, update the ``tag``,
203+
``branch``, or ``revision`` in ``dfetch.yaml`` and then run ``dfetch update``.
204+
*Dfetch* fetches the new version and attempts to re-apply the patch using fuzzy
205+
matching, so patches often survive minor context changes automatically.
206+
207+
.. code-block:: console
208+
209+
$ # 1. Edit dfetch.yaml: change tag v1.2.3 → v1.3.0
210+
$ dfetch update some-project
211+
212+
Three outcomes are possible:
213+
214+
**Patch applies cleanly** — you are done. Review the result, commit the
215+
updated manifest and the updated vendored files.
216+
217+
**Patch applies with fuzz warnings** — the patch applied but the context lines
218+
shifted slightly. The files are in the correct state. Run
219+
``dfetch update-patch some-project`` to refresh the patch against the new
220+
baseline so it stays clean for future upgrades:
221+
222+
.. code-block:: console
223+
224+
$ git add some-project/
225+
$ git commit -m "vendor: update some-project to v1.3.0"
226+
$ dfetch update-patch some-project
227+
$ git add some-project.patch
228+
$ git commit -m "patches: refresh some-project.patch for v1.3.0"
229+
230+
**Patch fails to apply** — the upstream changes conflict with the local edits
231+
tracked in the patch. Resolve the conflict manually by editing the vendored
232+
files, then use ``dfetch update-patch`` to record the resolved state:
233+
234+
.. code-block:: console
235+
236+
$ # Manually resolve conflicts in some-project/
237+
$ git add some-project/
238+
$ git commit -m "vendor: update some-project to v1.3.0 with resolved conflicts"
239+
$ dfetch update-patch some-project
240+
$ git add some-project.patch
241+
$ git commit -m "patches: update some-project.patch for v1.3.0"
242+
140243
.. _patching-upstream:
141244

142245
Contributing the patch upstream
@@ -152,10 +255,15 @@ for a project:
152255
$ dfetch format-patch some-project
153256
154257
This writes a ``formatted-some-project.patch`` file (or one file per patch if
155-
there are several) that is ready to share with the upstream project.
258+
there are several) in the current directory. Use ``--output-directory`` to
259+
place the formatted files in a specific location:
260+
261+
.. code-block:: console
156262
157-
Before sending it, do a dry-run check to confirm it applies cleanly to a local
158-
clone of the upstream repository:
263+
$ dfetch format-patch some-project --output-directory patches/upstream
264+
265+
Before sending a patch, do a dry-run check to confirm it applies cleanly to a
266+
local clone of the upstream repository:
159267

160268
.. tabs::
161269

@@ -188,3 +296,41 @@ clone of the upstream repository:
188296
.. asciinema:: ../asciicasts/format-patch.cast
189297

190298
See :ref:`format-patch` in the command reference for all options.
299+
300+
.. _patching-troubleshooting:
301+
302+
Troubleshooting
303+
---------------
304+
305+
**"No diffs found"**
306+
307+
``dfetch diff`` found no changes between the working tree and the upstream
308+
baseline recorded in ``.dfetch_data.yaml``. If you expected changes, make
309+
sure the edits are in the vendored directory and are not excluded by your
310+
VCS ignore rules. If the metadata file is missing, run
311+
``dfetch update some-project`` first to re-establish the baseline.
312+
313+
**Patch fails to apply after an upstream bump**
314+
315+
The upstream version introduced changes that conflict with the local edits
316+
in the patch. Follow the manual resolution workflow in
317+
:ref:`patching-upstream-bump`: edit the vendored files to the desired
318+
state, commit them, then run ``dfetch update-patch`` to regenerate the
319+
patch from the resolved working tree.
320+
321+
**"skipped — Uncommitted changes"**
322+
323+
``dfetch update-patch`` detected unstaged or staged-but-uncommitted changes
324+
in the project directory. Commit or stash those changes before running the
325+
command so the patch calculation starts from a clean state.
326+
327+
**"skipped — the project was never fetched"**
328+
329+
Run ``dfetch update some-project`` first. The project must exist on disk
330+
before a patch can be updated.
331+
332+
**"skipped — there is no patch file"**
333+
334+
The project has no ``patch:`` entry in the manifest. Use
335+
``dfetch diff some-project`` to create the initial patch, then add it to
336+
the manifest as described in :ref:`patching-wire`.

0 commit comments

Comments
 (0)