<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>emre şahin's digital garden 🍃 - dvc</title>
    <link>https://emresahin.net/tags/dvc/</link>
    <description>Posts in the dvc tag</description>
    <language>en</language>
    <managingEditor>contact@emresahin.net (Emre Şahin)</managingEditor>
    <lastBuildDate>Tue, 15 Sep 2026 19:46:32 +0000</lastBuildDate>
    <atom:link href="https://emresahin.net/tags/dvc/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Differences between DVC and Xvc</title>
      <published>2024-07-17T09:57:44+00:00</published>
      <updated>2024-07-17T09:57:44+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Wed, 17 Jul 2024 09:57:44 +0000</pubDate>
      <link>https://emresahin.net/differences-between-dvc-and-xvc/</link>
      <guid isPermaLink="true">https://emresahin.net/differences-between-dvc-and-xvc/</guid>
      <description>I wrote this on Reddit; let’s put it here too. Full list of similarities and differences is rather long. Let me summarize it. Xvc has different commands; xvc file track is used instead of dvc add . Xvc doesn’t add files (like .dvc files) to your repository and keeps all metadata tracking under th...</description>
      <category>xvc</category>
      <category>MLOps</category>
      <category>xvc</category>
      <category>dvc</category>
      <category>mlops</category>
      <category>data-versioning</category>
      <category>rclone</category>
      <category>s5cmd</category>
      <category>data-science</category>
      <content:encoded><![CDATA[<p>I wrote <a href="https://www.reddit.com/r/mlops/comments/1e4vvv3/xvc_a_free_as_in_freedom_cli_and_python_tool_to/">this</a> on Reddit; let’s put it here too.</p>
<p><a href="https://docs.xvc.dev/start/from-dvc">Full list of similarities and differences</a> is rather long. Let me summarize it.</p>
<p>Xvc has different commands; <code>xvc file track</code> is used instead of <code>dvc add</code>. Xvc doesn’t add files (like <code>.dvc</code> files) to your repository and keeps all metadata tracking under the <code>.xvc</code> directory. <a href="https://docs.xvc.dev/ref/xvc-file-recheck"><em>Checkout method</em></a> is per-file, not configured globally, so you can keep track of your data directory with symlinks and your model directory as copies. Xvc uses BLAKE3 as the default hashing algorithm, and you can configure this to be BLAKE2, SHA-2, or SHA-3.</p>
<p>Pipelines are not defined using YAML files. You can write a shell script with <code>xvc pipeline step ...</code> or use Python <code>xvc.pipeline().step().dependency(step_name="preprocess", param="hyperparams.yaml::batch_size")</code> to define pipelines first. Then you can use <code>xvc pipeline export</code> and <code>xvc pipeline import</code> to modify the pipeline in YAML, JSON, or TOML.</p>
<p>There are <a href="https://docs.xvc.dev/ref/xvc-pipeline-step-dependency">more dependency options</a>; e.g., a pipeline step may depend on a text file partially, by <a href="https://docs.xvc.dev/ref/xvc-pipeline-step-dependency#regex-item-dependencies">regex</a> or by the <a href="https://docs.xvc.dev/ref/xvc-pipeline-step-dependency#line-item-dependencies">line</a> options. There is a <a href="https://docs.xvc.dev/ref/xvc-pipeline-step-dependency#generic-command-dependencies">generic dependency</a> option; the output of a shell command can be used as a dependency to a step.</p>
<p><a href="https://docs.xvc.dev/ref/xvc-storage-new">Remote storage options</a> are rather limited for Xvc; local, ssh+rsync, and S3-compatible storages are supported for now. There is also a <code>generic</code> storage option where you can define upload and download commands for the tool you’re using, e.g., <code>rclone</code> or <code>s5cmd</code>, and Xvc can use it. I’ll add Azure and rclone as natively supported storage options eventually, but I don’t like the idea of keeping credentials, so there won’t be any OAuth-required storage options, e.g., Google Drive. (You’ll be able to use these through rclone, though.) All Xvc storages use environment variables for authentication.</p>
<p>Xvc doesn’t have experiment tracking yet. <a href="https://docs.xvc.dev/how-to/git-branches">You can use <code>--from-ref</code> and <code>--to-branch</code> options</a> to store artifacts from the pipeline to different branches. I’ll add features to run pipelines and commands quickly and compare these eventually (I need one too), but it may take some time.</p>
<p>Xvc doesn’t track anything about the user. It shouldn’t make any network connections if you don’t specifically ask it to do so. I’m planning to add binaries that only do file operations or pipeline operations, so if someone doesn’t need pipeline features, they will simply use <code>xvc-file</code>.</p>]]></content:encoded>
    </item>
    <item>
      <title>A Brief History of Xvc</title>
      <published>2024-01-22T09:17:15+00:00</published>
      <updated>2024-01-22T09:17:15+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Mon, 22 Jan 2024 09:17:15 +0000</pubDate>
      <link>https://emresahin.net/a-brief-history-of-xvc/</link>
      <guid isPermaLink="true">https://emresahin.net/a-brief-history-of-xvc/</guid>
      <description>In the first months of 2021, I decided to return to life after a long legal battle for divorce. Covid was still raging. I wasn’t keen to start a company or work in my country due to my half-deaf ears. I decided to find some open source projects and contribute, maybe get recognition, maybe hired. ...</description>
      <category>xvc</category>
      <category>development</category>
      <category>free software</category>
      <category>Software Engineering</category>
      <category>xvc</category>
      <category>history</category>
      <category>dvc</category>
      <category>Rust</category>
      <category>MLOps</category>
      <category>Open Source</category>
      <category>Iterative.ai</category>
      <category>Git Annex</category>
      <category>serde</category>
      <category>Blake3</category>
      <category>PyO3</category>
      <content:encoded><![CDATA[<p>In the first months of 2021, I decided to return to life after a long legal battle for divorce. Covid was still raging. I wasn’t keen to start a company or work in my country due to my half-deaf ears. I decided to find some open source projects and contribute, maybe get recognition, maybe hired.</p>
<p>I saw an ad on Stack Overflow Jobs those days about <em>employment by contributing to open source projects.</em> I applied to that. A few weeks later, the CTO of [iterative.ai] got in touch and I started working on DVC documentation. Initially on a per-hour basis, and after May 2021, as a full-time employee.</p>
<p>Initially, I liked the tool we were building very much. The team was awesome. (Still, they are.) It was one of the best periods of my life, especially in my turbulent still-ongoing-divorce-period pressures. I know I will always miss them.</p>
<p>My job was learning DVC, documenting it, and helping newcomers grasp it easily. It was a fun job. Until then, I didn’t see myself as a technical writer. English is not my native tongue and I never have lived in an English-speaking country. Nevertheless, I think I wasn’t <em>too bad</em> at it.</p>
<p>When I was first learning the tool, I began to use it everywhere. I was an avid user of Git Annex once. DVC looked better. I don’t remember why I lost interest in Git Annex after many years, but it was probably related to symbolic links not working on Windows (or on Termux). DVC had multiple ways of connecting the cache and the files in the workspace, including hardlinks and copy, so it was a breath of fresh air for me.</p>
<p>I began to use it for my large collections. Keeping track of my binary files in Git was something I always desired. Git is the <em>least sucking</em> version control system among the ones I used previously (SVN, hg, darcs…) and I’d rather keep using it everywhere rather than learning new tools for binary files.</p>
<p>After some time I began to use the tool for my personal file collections. I noticed its performance became a burden. I was tracking maybe a few gigabytes of files with it and basic file operations became slower as I added more. I noticed I was becoming distracted after I wrote a <code>dvc</code> command. It took some time to confess that the tool I liked once and was earning my salary with was not a tool that I liked to use.</p>
<p>I don’t know what <em>real professionals</em> would do at this point. I never had a good LinkedIn profile. When I met a similar problem with the example repository that’s supposed to contain 70,000 small files, I brought the issue forward. I wrote a shell script that was basically doing the same thing as <code>dvc add</code> and it worked much faster than the actual command. The shell script was naïve and I thought DVC must have <em>at least</em> that level of speed. It didn’t. Simply calling <code>md5sum</code> on files and copying them to appropriate location in <code>.dvc/cache</code> was way faster. How could this be?</p>
<p>I had cursory observations on the codebase. I know some decisions (like a large central class that connects everything, separate <code>.dvc</code> files for each tracked file) that may lead to degradation. Although I don’t see it as <em>the problem</em>, Python was also not helpful. These are rough observations.</p>
<p>It was September 2021. I was also teaching myself Rust. I wrote an email to the CTO and CEO of the company to request a sabbatical to work on DVC. My plan was to rewrite certain portions (or commands) in Rust and wrap them with PyO3. It could fail. So to have <em>skin in the game</em>, I said I’ll work for free during this time and if I fail to make DVC faster for some reason, I’ll return to my writing position.</p>
<p>They didn’t accept. I didn’t try to persuade them. The decision was rational and although I’d say <em>go ahead and see what happens</em> if I were in their shoes just to make my employee happy, they aren’t <em>crazy-managers</em> as I once was. Probably there are many factors that I’m not aware of. I returned to my post and continued to write documentation for another 9 months. In the meantime I studied Rust and thought about how I could architect a similar tool. Where does DVC go wrong?</p>
<p>In April 2022, I informed the CTO that I’d like to take a sabbatical for my book. I have a political-SF book and after the Ukrainian war started with a (albeit minor) probability of nuclear attack <em>on the other shore of Black Sea</em>, I thought it’s not a time to work on something I stopped liking. My performance in the last quarter was also not something I was proud of. I didn’t feel good.</p>
<p>When I retired to sabbatical in July though, while writing the book, I thought writing the software that I wanted to see was also <em>something on my mind before nuclear war.</em> I had notes about the architecture I was planning. I wanted to see if I could apply an Entity-Component System to this basic problem, without any Object-Oriented conceptions. I believe it looks cool. I’m still simplifying and testing the idea, and it looks better to my mind than mixing data and functions for no reason.</p>
<p>After I made the repository public, I resigned from Iterative.</p>
<p>In a sense, Xvc owes its existence to DVC, and the name is a tribute to this. I hope they squash their bugs, and improve their user experience, and be a long-term player in the crowded market they are in. I don’t intend to be a “competitor”, because I prefer being developer/architect rather than a “technical steward to VC money”, and the license of Xvc is GPL-3 to signal this.</p>
<p>The Xvc command line interface, however, is as different as it can be from DVC. The command names are different; DVC has commands similar to Git (<code>push</code>, <code>fetch</code>, <code>pull</code>, <code>commit</code>), while Xvc tries to be different from Git to reduce the user’s mental load. For example, as a writer, I noticed that “Git remotes” and “DVC remotes” was confusing, so I called them “Xvc storages”. DVC calls the units of a pipeline <em>stages</em>; the same concept is called <em>steps</em> in Xvc, because <em>stage</em> in Git is something completely different.</p>
<p>Internally, the architecture is also very different. Xvc uses serialization (with serde) instead of YAML. It can export/import pipelines from YAML (or JSON), but YAML is not as central as in DVC. (I believe YAML is overused in our industry, and it’s an employment guarantee for another generation of developers but there is better work than keeping up a half-baked configuration format.) Xvc doesn’t keep its artifacts in the user’s workspace (except <code>.xvcignore</code> files). They are all stored in the <code>.xvc/</code> directory. The DVC way of doing things makes merging <code>.dvc</code> files easier. To overcome the problems caused by merging large metadata files, Xvc keeps track of events and replays them to get the final state of the repository. All metadata storage and retrieval operations revolve around the <code>XvcStore&lt;T&gt;</code> struct in Xvc. Typically, if the user runs an <code>xvc</code> command, only the updated store events (added files, changed pipelines, etc.) are stored. There are optimizations in this front, but I profile first and optimize later.</p>
<p>Algorithms for data digests are configurable; by default Xvc uses Blake3, but it is configurable to use SHA2-256, SHA3-256, or Blake2s. It can be modified to use any 256-bit digest quickly. There are some features that are not found in DVC, and more will come. So, although I’m solving a similar problem, Xvc is not “DVC rewritten in Rust,” it’s a different tool completely.</p>
<p>Currently, it doesn’t have as much eye candy as DVC. In time, I plan to add Python, Julia, and R APIs, notebook integration, experiment tracking (without relying on Git internals), data labeling and filtering, and other MLOps features. I’m building with a goal to make these features available without making the rest of the software slower.</p>
<p>I’ve found the tool I was looking for to track my kids’ photos and Ottoman OCR datasets in a Git repository. I’m tracking more than 1TB of files in a single repository with Xvc and adding another 10TB looks feasible now.</p>]]></content:encoded>
    </item>
    <item>
      <title>Xvc Devlog - 221105</title>
      <published>2022-11-07T10:04:00+00:00</published>
      <updated>2022-11-07T10:04:00+00:00</updated>
      <author>Emre Şahin</author>
      <pubDate>Mon, 07 Nov 2022 10:04:00 +0000</pubDate>
      <link>https://emresahin.net/xvc-devlog---221105/</link>
      <guid isPermaLink="true">https://emresahin.net/xvc-devlog---221105/</guid>
      <description>It’s Saturday, November 5th. The best part of free software development seems to be being able to work whenever you want, including Saturdays. Ah yeah, when you work for free, you can do so at any time you want, perhaps. You also don’t have team members, and that means when you sit in front of th...</description>
      <category>devlog</category>
      <category>Software Development</category>
      <category>xvc</category>
      <category>git</category>
      <category>dvc</category>
      <category>git-lfs</category>
      <category>git-annex</category>
      <category>shell</category>
      <category>process</category>
      <category>which</category>
      <category>VCS</category>
      <content:encoded><![CDATA[<p>It’s Saturday, November 5th. The best part of free software development seems to be being able to work whenever you want, including Saturdays.</p>
<p>Ah yeah, when you work for free, you can do so at any time you want, perhaps. You also don’t have team members, and that means when you sit in front of this, you can move it.</p>
<p>Umm, right. Let’s take a look at <a href="https://github.com/iesahin/xvc/pulls">the outstanding PRs</a>.</p>
<p>You have a <a href="https://github.com/iesahin/xvc/pull/93">documentation PR#93</a>. You also have work that you’ve <a href="https://github.com/iesahin/xvc/issues/74">begun to integrate Git into.</a> I think it’s better to focus on the latter today.</p>
<p>Right. Let’s think about the relationship between Git and Xvc. I believe we should identify a general relation to avoid ending up in a mess like DVC and Git.</p>
<p>Why do you think the DVC and Git relationship is a mess?</p>
<p>They don’t automate common Git operations like a commit after <code>dvc add</code>. There is only <em>auto-stage</em>, and that’s turned off by default. This makes it seem that DVC wants to intervene as little as possible with the user’s Git workflow. That’s understandable. I support this. But on the other hand, they use the <code>.git/</code> directory itself to store and manage experiments in a custom way that creates custom stash objects for experiments. This is against the principle of minimum intervention.</p>
<p>So this makes it a mess?</p>
<p>The mess, in my opinion, is caused by the second factor. If DVC doesn’t perform any Git operations, that’s alright. It was intended to be VCS-agnostic. Then experiments came and used Git internals in a way that no other similar tool uses.</p>
<p>Git-LFS and Git-Annex seem to use some non-standard mechanisms as well.</p>
<p>Ok. Not <em>no other tool</em> uses, but in a way that no other tool has used.</p>
<p>You know, GitHub PRs are also stored in a similar way. They also use non-standard machinery.</p>
<p>Yeah, but these tools are all Git-specific tools. They accept the <em>dominion of Git</em>, and don’t try to bring any VCS-agnosticism.</p>
<p>And Xvc tries to have this agnosticism?</p>
<p>I believe the initial design of DVC, which aims to be VCS-agnostic or being able to run without a VCS, is valuable. I like the idea behind Git, but the interface and implementation show that it’s a <em>gradual development.</em> There is no library behind it.</p>
<p>Libgit?</p>
<p><a href="https://libgit2.org">Libgit2</a> is something different. Although it’s said to have some common code, it doesn’t support all features. Git is command-line software with a mix of scripts and compiled executables, and not all code seems to be written in a way that could be used by external tools.</p>
<p>Hmm. <a href="https://github.com/iesahin/xvc/issues/74#issuecomment-1302531362">The comment</a> you added to the issue says <code>git stash push --staged</code> is not available in libgit2. Can’t you mimic it like DVC does for branches?</p>
<p>I don’t want to depend on Git at that level.</p>
<p>So, you’ll be using the CLI and shell for Git?</p>
<p>Yes, I believe, at the moment, before any performance tests, that this doesn’t matter much. Running Git commands once in a while using the shell shouldn’t make much difference in overall performance.</p>
<p>Then you’ll use it like a command-line tool, like the user?</p>
<p>Yes, and I’ll make it run outside of the usual threads. All Git will be like a sandwich, wrapping around Xvc operations. If there are <code>--git-ref</code> instructions in an <code>xvc</code> command, it will be run before Xvc performs the command, and if there are any changes in Xvc metafiles, they will be committed to the current branch.</p>
<p>Like</p>
<pre class="mermaid">graph LR

co["git checkout"] --&gt; xvc
xvc --&gt; cm["git commit"]

</pre>

<p>The first could be a branch as well. So we have:</p>
<pre class="mermaid">graph LR

br["git branch"] --&gt; xvc
co["git checkout"] --&gt; xvc
xvc --&gt; cm["git commit"]

</pre>

<p>Looks sensible. How will you reflect these in the command line?</p>
<p>With something like <code>xvc --git-checkout my-branch file list</code></p>
<p>Hmm, and for a branch?</p>
<p>I think instead of different options for <code>branch</code>, <code>checkout</code> or <code>tag</code>, we can have a <code>git-ref</code> option that marks the option as a git reference. It will be checked out, or created as a branch from the current one if it doesn’t exist.</p>
<p>I think creating a branch is not a good idea. It should be explicit. You can just send the <code>--git-ref</code> value to <code>git checkout</code> and perform the Xvc operation. If the user wants to create a branch, I think they can do it themselves.</p>
<p>What about storing the results in a branch? After adding a bunch of files, they may want to store them in another branch, maybe?</p>
<p>That’s sensible. We can have another option, like <code>--to-branch</code> in certain operations.</p>
<p>Or in the <code>xvc</code> command as a general option. In that case, we can change the option names to <code>--from-ref</code> and <code>--to-branch</code>. It will be like:</p>
<pre class="mermaid">graph LR

fr["git checkout $(--from-ref)"] --&gt; xvc
xvc --&gt; tb["git checkout --branch $(--to-branch)"]
tb --&gt; co["git add .xvc &amp;&amp; git commit -m 'xvc cmd'"]

</pre>

<p>If no such options are given, xvc will run without branching, right?</p>
<p>Yep. <code>--from-ref</code> and <code>--to-branch</code> options are just shortcuts for user behavior. Any other VCS tool could be used this way. We don’t need to integrate Git at the library level.</p>
<p>This brings up the question of portability, though. When you aim for the software to be portable, you can’t rely on the existence of Git on the host, right?</p>
<p>I think a <code>git.command</code> option in the configuration is a good idea. Xvc will issue a warning if it can’t run the commands.</p>
<p>Will you use the shell to run this command? Otherwise no <code>$PATH</code> configuration is possible, you know.</p>
<p>I believe that could be another option: <code>git.use_shell</code>. If <code>git.command</code> is set to an absolute path, Xvc may use it without the shell. Otherwise, it can use the shell. Running the process directly will make it faster and more secure.</p>
<p>There is also this option to run Xvc in another process. Because we may access Git in the shell that runs Xvc, and if we can access it, maybe we don’t need shell execution in the process.</p>
<p>That’s a cool idea. But I wouldn’t add that extra complexity. Instead, we can try to find the <code>git</code> executable if <code>git.command</code> is not an absolute path. If <code>git.command = /usr/bin/git</code> in the configuration, we use it as is. Otherwise, we can get <code>$PATH</code> or <code>%PATH%</code> from the environment and search for <code>git.command</code> in that to find the exact executable.</p>
<p>It looks like there is a crate called <a href="https://crates.io/crates/which">which</a> that does exactly what we are looking for.</p>
<p>Ah, cool. Then we can just use that to find the executable and run it. We don’t need to drop to a shell.</p>
<p>Yep. Let’s go back to implementation now.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
