Sometimes I find myself working on a project (possibly not mine) and wanting to track changes I’m doing in that project. But either the project is not suitable for a full-blown version control system like Git (because I’m not necessarily talking about software development here) or I don’t want to (or can’t) introduce this tool into the workflow.
I was wondering whether I can use the same method that container runtimes are using to separate static container images from ephemeral containers. The answer turns out to be: yes!
Enter OverlayFS: as the name suggest, this “filesystem” allows mounting one filesystem on top of another one and interacting with the merged result. This works not only for entire filesystems, but also for individual directories.
My use case is the simplest possible scenario for an overlay filesystem:
- the lower layer contains the original work and should remain unchanged at all times
- the upper layer contains the changes made “to” the original project
- both layers are merged in a mount point that represents the current work
So far the theory, let’s put this into practice.
We’ll need four different directories.
At the beginning,
workdir and the mount point (
merged) should be empty.
workdir directory needs to be on the same filesystem as
Now you can see the merged result of
As this StackOverflow post points out, the error messages from the overlay driver can very be misleading. More accurate error messages are available through the kernel’s diagnostic messages:
mount: /home/jack/merged: special device overlay does not exist. $ dmesg [ 5072.133631] overlayfs: failed to resolve '/home/jack/original': -2
mount: /home/jack/merged: wrong fs type, bad option, bad superblock on overlay, missing codepage or helper program, or other error. $ dmesg [ 5507.655432] overlayfs: unrecognized mount option "workdir=" or missing value
When we create a new file or modify an existing file in the overlayed filesystem (
merged directory), it will appear in the upper layer (
$ tree ├── changes ├── merged │ └── greetings.txt ├── original │ └── greetings.txt └── work └── work $ touch merged/hello-world.txt $ tree ├── changes │ └── hello-world.txt ├── merged │ ├── greetings.txt │ └── hello-world.txt ├── original │ └── greetings.txt └── work └── work $ echo "Have a great day!" >> merged/greetings.txt $ tree ├── changes │ ├── greetings.txt │ └── hello-world.txt ├── merged │ ├── greetings.txt │ └── hello-world.txt ├── original │ └── greetings.txt └── work └── work
Since any file changes are automatically copy-on-write, this gives me a great overview of the changes I have made to a particular project with file-level granularity.
For more detailed change inspections, I can still fallback to good old
diff since I know which files to look at.
The overlay filesystem can be unmounted (
sudo unmount ./merged) and later mounted again with the same command as above, since the changes are persisted in the upper layer (
Additionally, multiple lower directories can be used:
For more details, please refer to the Linux kernel’s documentation on OverlayFS (it’s very accessible).