Update projects¶
dfetch update fetches every dependency listed in dfetch.yaml and
places the requested version in its destination folder. VCS type (Git, SVN,
or plain archive) is detected automatically.
Fetching all projects — fetch all projects at once
Updating a single project — update a single project
Overwriting local changes — overwrite local changes
Sub-manifests — nested manifests in dependencies
Git submodules — Git submodules inside dependencies
Fetching all projects¶
Run without arguments to fetch every project in the manifest:
$ dfetch update
Dfetch reads dfetch.yaml, resolves each project’s VCS type, and writes
the requested revision into the destination folder. A .dfetch_data.yaml
metadata file is created inside each destination so Dfetch can track what
version is present.
Example: Git projects are specified in the manifest
Given the manifest 'dfetch.yaml'
"""
manifest:
version: '0.0'
remotes:
- name: github-com-dfetch-org
url-base: https://github.com/dfetch-org/test-repo
projects:
- name: ext/test-repo-rev-only
revision: e1fda19a57b873eb8e6ae37780594cbb77b70f1a
dst: ext/test-repo-rev-only
- name: ext/test-rev-and-branch
revision: 8df389d0524863b85f484f15a91c5f2c40aefda1
branch: main
dst: ext/test-rev-and-branch
- name: ext/test-repo-tag-v1
tag: v1
dst: ext/test-repo-tag-v1
"""
When I run "dfetch update"
Then the following projects are fetched
| path |
| ext/test-repo-rev-only |
| ext/test-rev-and-branch |
| ext/test-repo-tag-v1 |
Example: Tag is updated in manifest
Given the manifest 'dfetch.yaml'
"""
manifest:
version: '0.0'
projects:
- name: ext/test-repo-tag
url: https://github.com/dfetch-org/test-repo
tag: v1
"""
And all projects are updated
When the manifest 'dfetch.yaml' is changed to
"""
manifest:
version: '0.0'
projects:
- name: ext/test-repo-tag
url: https://github.com/dfetch-org/test-repo
tag: v2.0
"""
And I run "dfetch update"
Then the output shows
"""
Dfetch (0.13.0)
ext/test-repo-tag:
> Fetched v2.0
"""
Example: Version check ignored when force flag is given
Given the manifest 'dfetch.yaml'
"""
manifest:
version: '0.0'
projects:
- name: ext/test-repo-tag
url: https://github.com/dfetch-org/test-repo
tag: v1
"""
And all projects are updated
When I run "dfetch update --force"
Then the output shows
"""
Dfetch (0.13.0)
ext/test-repo-tag:
> Fetched v1
"""
Example: SVN projects are specified in the manifest
Given the manifest 'dfetch.yaml'
"""
manifest:
version: '0.0'
remotes:
- name: cunit
url-base: svn://svn.code.sf.net/p/cunit/code
default: true
- name: cutter
url-base: svn://svn.code.sf.net/p/cutter/svn/cutter
projects:
- name: cunit-svn-rev-only
revision: '176'
vcs: svn
dst: ext/cunit-svn-rev-only
- name: cunit-svn-rev-and-branch
revision: '156'
vcs: svn
branch: mingw64
dst: ext/cunit-svn-rev-and-branch
- name: cutter-svn-tag
vcs: svn
tag: 1.1.7
src: acmacros
dst: ext/cutter-svn-tag
remote: cutter
"""
When I run "dfetch update"
Then the following projects are fetched
| path |
| ext/cunit-svn-rev-only |
| ext/cunit-svn-rev-and-branch |
| ext/cutter-svn-tag |
Example: Directory in a non-standard SVN repository can be fetched
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: SomeProject
url: some-remote-server/SomeProject
src: SomeFolder/
branch: ' '
"""
And a non-standard svn-server "SomeProject" with the files
| path |
| SomeFolder/SomeFile.txt |
| SomeOtherFolder/SomeOtherFile.txt |
When I run "dfetch update"
Then 'MyProject' looks like:
"""
MyProject/
SomeProject/
.dfetch_data.yaml
SomeFile.txt
dfetch.yaml
"""
Example: SVN repository with a tags can be fetched
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: SomeProject
url: some-remote-server/SomeProject
tag: 'v1.2.3'
- name: SomeOtherProject
url: some-remote-server/SomeOtherProject
tag: 'v 1&;{6}'
"""
And a svn-server "SomeProject" with the tag "v1.2.3"
And a svn-server "SomeOtherProject" with the tag "v 1&;{6}"
When I run "dfetch update"
Then 'MyProject' looks like:
"""
MyProject/
SomeOtherProject/
.dfetch_data.yaml
README.md
SomeProject/
.dfetch_data.yaml
README.md
dfetch.yaml
"""
Example: Tar.gz archive project is fetched
Given an archive "SomeProject.tar.gz" with the files
| path |
| README.md |
| src/main.c |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.tar.gz
vcs: archive
"""
When I run "dfetch update" in MyProject
Then 'MyProject' looks like:
"""
MyProject/
SomeProject/
.dfetch_data.yaml
README.md
src/
main.c
dfetch.yaml
"""
Example: Zip archive project is fetched
Given an archive "SomeProject.zip" with the files
| path |
| README.md |
| include/lib.h |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.zip
vcs: archive
"""
When I run "dfetch update" in MyProject
Then 'MyProject' looks like:
"""
MyProject/
SomeProject/
.dfetch_data.yaml
README.md
include/
lib.h
dfetch.yaml
"""
Example: Archive projects with sha256, sha384 and sha512 hash verification are fetched
Given an archive "SomeProject.tar.gz" with the files
| path |
| README.md |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject-sha256
url: some-remote-server/SomeProject.tar.gz
vcs: archive
integrity:
hash: sha256:<archive-sha256>
- name: SomeProject-sha384
url: some-remote-server/SomeProject.tar.gz
vcs: archive
integrity:
hash: sha384:<archive-sha384>
- name: SomeProject-sha512
url: some-remote-server/SomeProject.tar.gz
vcs: archive
integrity:
hash: sha512:<archive-sha512>
"""
When I run "dfetch update" in MyProject
Then 'MyProject' looks like:
"""
MyProject/
SomeProject-sha256/
.dfetch_data.yaml
README.md
SomeProject-sha384/
.dfetch_data.yaml
README.md
SomeProject-sha512/
.dfetch_data.yaml
README.md
dfetch.yaml
"""
Example: Archive with incorrect sha256 hash is rejected
Given an archive "SomeProject.tar.gz" with the files
| path |
| README.md |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.tar.gz
vcs: archive
integrity:
hash: sha256:0000000000000000000000000000000000000000000000000000000000000000
"""
When I run "dfetch update" in MyProject
Then the output shows
"""
Dfetch (0.13.0)
Hash mismatch for SomeProject! sha256 expected 0000000000000000000000000000000000000000000000000000000000000000
"""
Example: Specific directory from archive can be fetched
Given an archive "SomeProject.tar.gz" with the files
| path |
| src/main.c |
| src/lib.c |
| tests/test_main.c |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.tar.gz
vcs: archive
src: src/
"""
When I run "dfetch update" in MyProject
Then 'MyProject' looks like:
"""
MyProject/
SomeProject/
.dfetch_data.yaml
lib.c
main.c
dfetch.yaml
"""
Example: Files can be ignored when fetching from archive
Given an archive "SomeProject.tar.gz" with the files
| path |
| README.md |
| src/main.c |
| tests/test_main.c |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.tar.gz
vcs: archive
ignore:
- tests
"""
When I run "dfetch update" in MyProject
Then 'MyProject' looks like:
"""
MyProject/
SomeProject/
.dfetch_data.yaml
README.md
src/
main.c
dfetch.yaml
"""
Example: Archive is re-fetched when force flag is given
Given an archive "SomeProject.tar.gz" with the files
| path |
| README.md |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.tar.gz
vcs: archive
"""
And all projects are updated in MyProject
When I run "dfetch update --force" in MyProject
Then the output shows
"""
Dfetch (0.13.0)
SomeProject:
> Fetched some-remote-server/SomeProject.tar.gz
"""
Example: Multiple archive projects are fetched
Given an archive "LibA.tar.gz" with the files
| path |
| README.md |
And an archive "LibB.zip" with the files
| path |
| README.md |
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: LibA
url: some-remote-server/LibA.tar.gz
vcs: archive
- name: LibB
url: some-remote-server/LibB.zip
vcs: archive
"""
When I run "dfetch update" in MyProject
Then the following projects are fetched
| path |
| MyProject/LibA |
| MyProject/LibB |
Example: Archive with internal relative symlink using .. is fetched safely
Given an archive "SomeProject.tar.gz" with the files
| path |
| README.md |
| other/target.mk |
And the archive "SomeProject.tar.gz" contains a symlink "sub/dir/link.mk" pointing to "../../other/target.mk"
And the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: '0.0'
projects:
- name: SomeProject
url: some-remote-server/SomeProject.tar.gz
vcs: archive
"""
When I run "dfetch update" in MyProject
Then 'MyProject' looks like:
"""
MyProject/
SomeProject/
.dfetch_data.yaml
README.md
other/
target.mk
sub/
dir/
link.mk
dfetch.yaml
"""
And 'MyProject/SomeProject/sub/dir/link.mk' is a symlink pointing to '../../other/target.mk'
Updating a single project¶
Pass one or more project names to limit which entries are updated:
$ dfetch update mylib
$ dfetch update mylib myother
Overwriting local changes¶
By default Dfetch skips a project that is already at the requested version
or that has local modifications. Use --force (-f) to re-fetch and
overwrite regardless:
$ dfetch update --force mylib
Warning
Any unsaved local edits in the destination directory will be lost.
Capture them first with dfetch diff — see Patch a project for the
full patch workflow.
Sub-manifests¶
A fetched project may itself contain a dfetch.yaml. Dfetch reads it
after fetching and reports any further dependencies it finds, so you can
decide whether to vendor those as well.
To skip this check entirely:
$ dfetch update --no-recommendations
Example: Git projects are specified in the manifest
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: SomeProjectWithManifest
dst: third-party/SomeProjectWithManifest
url: some-remote-server/SomeProjectWithManifest.git
tag: v1
- name: SomeProjectWithoutManifest
dst: third-party/SomeProjectWithoutManifest
url: some-remote-server/SomeProjectWithoutManifest.git
tag: v1
"""
And a git-repository "SomeProjectWithManifest.git" with the manifest:
"""
manifest:
version: 0.0
remotes:
- name: github-com-dfetch-org
url-base: https://github.com/dfetch-org/test-repo
projects:
- name: SomeOtherProject
dst: SomeOtherProject
url: some-remote-server/SomeOtherProject.git
tag: v1
- name: ext/test-repo-tag-v1
tag: v1
"""
And a git repository "SomeProjectWithoutManifest.git"
When I run "dfetch update" in MyProject
Then the output shows
"""
Dfetch (0.13.0)
SomeProjectWithManifest:
> Fetched v1
> "SomeProjectWithManifest" depends on the following project(s) which are not part of your manifest:
(found in third-party/SomeProjectWithManifest/dfetch.yaml)
- name: SomeOtherProject
url: some-remote-server/SomeOtherProject.git
tag: v1
- name: ext/test-repo-tag-v1
url: https://github.com/dfetch-org/test-repo
tag: v1
SomeProjectWithoutManifest:
> Fetched v1
"""
And 'MyProject' looks like:
"""
MyProject/
dfetch.yaml
third-party/
SomeProjectWithManifest/
.dfetch_data.yaml
README.md
dfetch.yaml
SomeProjectWithoutManifest/
.dfetch_data.yaml
README.md
"""
Example: A project from a submanifest has an invalid manifest
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: SomeProject
dst: third-party/SomeProject
url: some-remote-server/SomeProject.git
tag: v1
"""
And a git-repository "SomeProject.git" with the manifest:
"""
very-invalid-manifest
"""
When I run "dfetch update" in MyProject
Then the output shows
"""
Dfetch (0.13.0)
SomeProject:
> Fetched v1
SomeProject/dfetch.yaml: Schema validation failed:
"very-invalid-manifest\n"
^ (line: 1)
found arbitrary text
"""
And 'MyProject' looks like:
"""
MyProject/
dfetch.yaml
third-party/
SomeProject/
.dfetch_data.yaml
README.md
dfetch.yaml
"""
Git submodules¶
When a Git dependency contains submodules, Dfetch fetches and resolves them
automatically — no extra manifest entries or git submodule commands are
needed. Each submodule is checked out at the exact revision pinned by the
parent repository.
$ dfetch update
Dfetch (0.13.0)
my-project:
> Found & fetched submodule "./ext/vendor-lib" (https://github.com/example/vendor-lib @ master - 79698c9…)
> Fetched master - e1fda19…
Nested submodules are resolved recursively. Pinned details for each
submodule are recorded in .dfetch_data.yaml and are visible in
Report.
Example: A project with a git submodule is fetched at the pinned revision
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: my-project-with-submodules
url: some-remote-server/SomeInterestingProject.git
"""
When I run "dfetch update"
Then the output shows
"""
Dfetch (0.13.0)
my-project-with-submodules:
> Found & fetched submodule "./ext/test-repo1" (some-remote-server/TestRepo.git @ master - 79698c99152e4a4b7b759c9def50a130bc91a2ff)
> Found & fetched submodule "./ext/test-repo2" (some-remote-server/TestRepo.git @ master - 79698c99152e4a4b7b759c9def50a130bc91a2ff)
> Fetched master - e1fda19a57b873eb8e6ae37780594cbb77b70f1a
"""
Then 'MyProject' looks like:
"""
MyProject/
dfetch.yaml
my-project-with-submodules/
.dfetch_data.yaml
README.md
ext/
test-repo1/
README.md
test-repo2/
README.md
"""
Example: A project with a git submodule that itself has a nested submodule is fetched at the pinned revision
Given a git repository "LeafProject.git"
And a git-repository "MiddleProject.git" with the following submodules
| path | url | revision |
| ext/leaf | some-remote-server/LeafProject.git | master |
And a git-repository "OuterProject.git" with the following submodules
| path | url | revision |
| ext/middle | some-remote-server/MiddleProject.git | master |
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: outer-project
url: some-remote-server/OuterProject.git
"""
When I run "dfetch update"
Then the output shows
"""
Dfetch (0.13.0)
outer-project:
> Found & fetched submodule "./ext/middle" (some-remote-server/MiddleProject.git @ master - 79698c99152e4a4b7b759c9def50a130bc91a2ff)
> Fetched master - e1fda19a57b873eb8e6ae37780594cbb77b70f1a
"""
Then 'MyProject' looks like:
"""
MyProject/
dfetch.yaml
outer-project/
.dfetch_data.yaml
README.md
ext/
middle/
README.md
ext/
leaf/
README.md
"""
Example: Submodule changes are reported in the project report
Given a fetched and committed MyProject with the manifest
"""
manifest:
version: 0.0
projects:
- name: my-project-with-submodules
url: some-remote-server/SomeInterestingProject.git
"""
When I run "dfetch report" in MyProject
Then the output shows
"""
Dfetch (0.13.0)
my-project-with-submodules:
- remote : <none>
remote url : some-remote-server/SomeInterestingProject.git
branch : master
tag : <none>
last fetch : 26/02/2026, 20:28:24
revision : 79698c99152e4a4b7b759c9def50a130bc91a2ff
patch : <none>
licenses : <none>
dependencies :
- path : ext/test-repo1
url : some-remote-server/TestRepo.git
branch : master
tag : <none>
revision : e1fda19a57b873eb8e6ae37780594cbb77b70f1a
source-type : git-submodule
- path : ext/test-repo2
url : some-remote-server/TestRepo.git
branch : master
tag : <none>
revision : 8df389d0524863b85f484f15a91c5f2c40aefda1
source-type : git-submodule
"""
Example: Subfolder is matched through a glob is fetched and submodules are resolved
Given a git-repository "GlobProject.git" with the following submodules
| path | url | revision |
| some_dir_a/ext/test-repo | some-remote-server/TestRepo.git | master |
Given the manifest 'dfetch.yaml' in MyProject
"""
manifest:
version: 0.0
projects:
- name: glob-project
url: some-remote-server/GlobProject.git
src: some_dir_*
"""
When I run "dfetch update"
Then the output shows
"""
Dfetch (0.13.0)
glob-project:
> Found & fetched submodule "./ext/test-repo" (some-remote-server/TestRepo.git @ master - 79698c99152e4a4b7b759c9def50a130bc91a2ff)
> Fetched master - e1fda19a57b873eb8e6ae37780594cbb77b70f1a
"""
Then 'MyProject' looks like:
"""
MyProject/
dfetch.yaml
glob-project/
.dfetch_data.yaml
ext/
test-repo/
README.md
"""