@@ -22,7 +22,44 @@ The full lifecycle looks like this:
22221. :ref: `patching-create ` — capture local edits as a ``.patch `` file with ``dfetch diff ``
23232. :ref: `patching-wire ` — reference the patch from the manifest so it is applied on every fetch
24243. :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+ .. tabs ::
42+
43+ .. tab :: Git
44+
45+ .. code-block :: console
46+
47+ $ dfetch update some-project
48+ $ git add some-project/
49+ $ git commit -m "vendor: add some-project v1.2.3"
50+
51+ .. tab :: SVN
52+
53+ .. code-block :: console
54+
55+ $ dfetch update some-project
56+ $ svn add some-project/
57+ $ svn commit some-project/ -m "vendor: add some-project v1.2.3"
58+
59+ You can then make edits to ``some-project/ `` and capture them with
60+ ``dfetch diff ``. Both committed and uncommitted edits are included in the
61+ generated patch, so you do not need to commit every intermediate step — only
62+ the clean upstream baseline matters.
2663
2764.. _patching-create :
2865
3875 $ dfetch diff some-project
3976
4077 *Dfetch * compares the working tree against the revision recorded in the
41- metadata file and writes a patch file named ``some-project.patch `` (or
42- ``some-project-N.patch `` if multiple patches already exist).
78+ metadata file and writes a patch file named ``some-project.patch ``.
4379
4480.. asciinema :: ../asciicasts/diff.cast
4581
82+ **What goes into the patch **
83+
84+ The diff captures all tracked modifications and any new untracked files in the
85+ vendored directory. Files ignored by your superproject's VCS (via
86+ ``.gitignore `` or ``svn:ignore ``) and the ``dfetch `` metadata file itself are
87+ always excluded.
88+
4689**Controlling which revisions are compared **
4790
4891By default, *Dfetch * uses the revision stored in the project's metadata as the
@@ -68,8 +111,8 @@ See :ref:`diff` in the command reference for all options.
68111Adding the patch to the manifest
69112---------------------------------
70113
71- Once you have a patch file, reference it from the project entry in
72- ``dfetch.yaml `` using the :ref: `patch ` attribute:
114+ Once you have a patch file, commit it to your repository and reference it from
115+ the project entry in ``dfetch.yaml `` using the :ref: `patch ` attribute:
73116
74117.. code-block :: yaml
75118
@@ -82,7 +125,23 @@ Once you have a patch file, reference it from the project entry in
82125 patch : some-project.patch
83126
84127 From this point on, every ``dfetch update `` will fetch the upstream source and
85- re-apply the patch on top.
128+ re-apply the patch on top. You can test the round-trip immediately:
129+
130+ .. code-block :: console
131+
132+ $ dfetch update --force some-project
133+
134+ The ``--force `` flag overwrites the working tree with the freshly fetched and
135+ patched version. Confirm the result looks right, then commit the manifest
136+ change and the patch file together.
137+
138+ **Organizing patch files **
139+
140+ Keep patch files alongside ``dfetch.yaml `` or in a dedicated subdirectory such
141+ as ``patches/ ``. *Dfetch * resolves patch paths relative to the manifest file,
142+ so as long as the path in the manifest matches the location on disk you have
143+ full flexibility. Committing the patch files to VCS ensures every team member
144+ and every CI run gets the same result.
86145
87146**Multiple patches **
88147
@@ -96,8 +155,10 @@ order:
96155 - 002-add-missing-header.patch
97156
98157 Patches are applied in the order listed. A good convention is to prefix each
99- file name with a zero-padded number so they sort correctly and their purpose is
100- clear at a glance.
158+ file name with a three-digit, zero-padded number (``001- ``, ``002- ``, …) so
159+ they sort correctly and their purpose is clear at a glance. The ``dfetch update-patch ``
160+ command always updates the **last ** patch in the list, so the earlier patches represent
161+ stable, settled changes and the final one accumulates ongoing work.
101162
102163See :ref: `patch ` in the manifest reference for the full attribute syntax.
103164
@@ -106,22 +167,29 @@ See :ref:`patch` in the manifest reference for the full attribute syntax.
106167Refreshing a patch
107168------------------
108169
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:
170+ As your local edits evolve, the existing patch file may become stale. Instead
171+ of manually regenerating it, run:
112172
113173.. code-block :: console
114174
115175 $ dfetch update-patch some-project
116176
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.
177+ This command:
178+
179+ 1. Re-fetches the upstream revision (without applying any patches).
180+ 2. Computes the diff between that clean baseline and your current working tree.
181+ 3. Overwrites the **last ** patch in the manifest list with the new diff.
182+ 4. Re-fetches the project and applies all patches so the working tree is left
183+ in the patched state.
184+
185+ It is safe to run repeatedly as you iterate on a fix. The upstream revision
186+ stays unchanged — only the patch file is updated.
187+
188+ .. note ::
120189
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 ``.
190+ ``update-patch `` requires the project directory to have **no uncommitted
191+ changes ** in the superproject. Commit your work first (Git users can also
192+ ``git stash ``), then run the command.
125193
126194.. asciinema :: ../asciicasts/update-patch.cast
127195
@@ -137,6 +205,77 @@ See :ref:`update-patch` in the command reference for all options.
137205
138206 .. scenario-include :: ../features/update-patch-in-svn.feature
139207
208+ .. _patching-upstream-bump :
209+
210+ Upgrading the upstream version
211+ -------------------------------
212+
213+ When you want to move to a new upstream release, update the ``tag ``,
214+ ``branch ``, or ``revision `` in ``dfetch.yaml `` and then run ``dfetch update ``.
215+ *Dfetch * fetches the new version and attempts to re-apply the patch using fuzzy
216+ matching, so patches often survive minor context changes automatically.
217+
218+ .. code-block :: console
219+
220+ $ # 1. Edit dfetch.yaml: change tag v1.2.3 → v1.3.0
221+ $ dfetch update some-project
222+
223+ Three outcomes are possible:
224+
225+ **Patch applies cleanly ** — you are done. Review the result, commit the
226+ updated manifest and the updated vendored files.
227+
228+ **Patch applies with fuzz warnings ** — the patch applied but the context lines
229+ shifted slightly. The files are in the correct state. Run
230+ ``dfetch update-patch some-project `` to refresh the patch against the new
231+ baseline so it stays clean for future upgrades:
232+
233+ .. tabs ::
234+
235+ .. tab :: Git
236+
237+ .. code-block :: console
238+
239+ $ git add some-project/
240+ $ git commit -m "vendor: update some-project to v1.3.0"
241+ $ dfetch update-patch some-project
242+ $ git add some-project.patch
243+ $ git commit -m "patches: refresh some-project.patch for v1.3.0"
244+
245+ .. tab :: SVN
246+
247+ .. code-block :: console
248+
249+ $ svn commit some-project/ -m "vendor: update some-project to v1.3.0"
250+ $ dfetch update-patch some-project
251+ $ svn commit some-project.patch -m "patches: refresh some-project.patch for v1.3.0"
252+
253+ **Patch fails to apply ** — the upstream changes conflict with the local edits
254+ tracked in the patch. Resolve the conflict manually by editing the vendored
255+ files, then use ``dfetch update-patch `` to record the resolved state:
256+
257+ .. tabs ::
258+
259+ .. tab :: Git
260+
261+ .. code-block :: console
262+
263+ $ # Manually resolve conflicts in some-project/
264+ $ git add some-project/
265+ $ git commit -m "vendor: update some-project to v1.3.0 with resolved conflicts"
266+ $ dfetch update-patch some-project
267+ $ git add some-project.patch
268+ $ git commit -m "patches: update some-project.patch for v1.3.0"
269+
270+ .. tab :: SVN
271+
272+ .. code-block :: console
273+
274+ $ # Manually resolve conflicts in some-project/
275+ $ svn commit some-project/ -m "vendor: update some-project to v1.3.0 with resolved conflicts"
276+ $ dfetch update-patch some-project
277+ $ svn commit some-project.patch -m "patches: update some-project.patch for v1.3.0"
278+
140279 .. _patching-upstream :
141280
142281Contributing the patch upstream
@@ -152,10 +291,15 @@ for a project:
152291 $ dfetch format-patch some-project
153292
154293 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.
294+ there are several) in the current directory. Use ``--output-directory `` to
295+ place the formatted files in a specific location:
296+
297+ .. code-block :: console
156298
157- Before sending it, do a dry-run check to confirm it applies cleanly to a local
158- clone of the upstream repository:
299+ $ dfetch format-patch some-project --output-directory patches/upstream
300+
301+ Before sending a patch, do a dry-run check to confirm it applies cleanly to a
302+ local clone of the upstream repository:
159303
160304.. tabs ::
161305
@@ -188,3 +332,41 @@ clone of the upstream repository:
188332.. asciinema :: ../asciicasts/format-patch.cast
189333
190334See :ref: `format-patch ` in the command reference for all options.
335+
336+ .. _patching-troubleshooting :
337+
338+ Troubleshooting
339+ ---------------
340+
341+ **"No diffs found" **
342+
343+ ``dfetch diff `` found no changes between the working tree and the upstream
344+ baseline recorded in ``.dfetch_data.yaml ``. If you expected changes, make
345+ sure the edits are in the vendored directory and are not excluded by your
346+ VCS ignore rules. If the metadata file is missing, run
347+ ``dfetch update some-project `` first to re-establish the baseline.
348+
349+ **Patch fails to apply after an upstream bump **
350+
351+ The upstream version introduced changes that conflict with the local edits
352+ in the patch. Follow the manual resolution workflow in
353+ :ref: `patching-upstream-bump `: edit the vendored files to the desired
354+ state, commit them, then run ``dfetch update-patch `` to regenerate the
355+ patch from the resolved working tree.
356+
357+ **"skipped - Uncommitted changes" **
358+
359+ ``dfetch update-patch `` detected uncommitted changes in the project
360+ directory. Commit those changes first (Git users can also ``git stash ``),
361+ then run the command so the patch calculation starts from a clean state.
362+
363+ **"skipped - the project was never fetched before" **
364+
365+ Run ``dfetch update some-project `` first. The project must exist on disk
366+ before a patch can be updated.
367+
368+ **"skipped - there is no patch file" **
369+
370+ The project has no ``patch: `` entry in the manifest. Use
371+ ``dfetch diff some-project `` to create the initial patch, then add it to
372+ the manifest as described in :ref: `patching-wire `.
0 commit comments