A simple local file versioning system in C#, created as a final project for Programming in C# Language (NPRG035). Tracks changes to individual text files, stores snapshots, and allows restoring older versions. All data is stored locally for simplicity.
A specification for the project can be found in specification.txt
.
Installation has been tested on Ubuntu 22.04. Clone or Download the project from GitHub and navigate to the project folder:
git clone [email protected]:sarka-stepankova/simple-file-versioning.git
cd simple-file-versioning
From now on, you are in the project folder.
Make sure to have the right .NET SDK installed before running this project. Check your .NET version via
dotnet --version
It should output something like 8.0.112
, meaning .NET 8.0 is installed.
If you don't have the correct version, download and intall it.
Go to ./simpleVersioning/
directory, where you will find Makefile. This Makefile assumes your filesystem follows /opt/
and /usr/local/bin
structure.
cd simpleVersioning
make install
- Build the project using:
dotnet publish -c Release -o ./publish
- copy the published files to designated directory
- create a symlink in /usr/local/bin, allowing you to run the tool globally.
Now you should be able to run sver
from anywhere.
After installation, you can use sver
from anywhere in your terminal. Below are available commands and how to use them:
To allow tracking of the file from specific directory, you need to first initialize the directory:
sver init
This creates a .versions
folder in your directory to store snapshots of tracked files.
To add the file to version control:
sver add <file>
This starts tracking <file>
, allowing snapshots to be created. You can add not only text files, but also binary files. This is an addition to the specification. Just keep in mind, that snapshots are created as a copy of current file, so your .version folder can get quite bloated.
And on the other hand remove a file from tracking:
sver remove <file>
This stops tracking <file>
and deletes its history from .versions/
.
When you feel like you want to store your file as a new version, you can create a snapshot of this file:
sver snapshot <file>
Note that this file has to be added to the version control first (sver add <file>
). If you want to find out which files are tracked, type sver list
. You can also create snapshots of all files:
sver snapshot
These two approaches save the current state of file(s) for future restoration.
To view changes in tracked files since the last snapshot:
sver status
And to list tracked files with their snapshots or list snapshots for a specific file:
sver list
sver list <file>
Restore a file to a specific snapshot version:
sver restore <file> <version>
sver restore cat.txt 2 # restore file cat.txt to the snapshot version 2
For summary of available commands listed above, run:
sver help
This project uses only standard .NET libraries. A few of them to name: System.IO (file handling, creating snapshots), System.Linq, System.Collections.Generic. No external NuGet packages are requiered.
To provide some context just from the structure and class names, the project is divided into three main folders:
- Commands/
- Services/
- Utils/
The entry point is the terminal. The Commands/ folder contains CommandHandler
which responses to a command request and executes the given command.
To help organize commands and execute them from handler, there is ICommand
interface with a single Execute() method. All Command classes (AddCommand, HelpCommand, ...) implement this interface.
Alongside the command handler, the Services/ folder contains core logic, such as file tracking and snapshot management (FileTracker, ListService and SnapshotService).
To separate service logic from the outer parts of application (such as commands calling services), the VersioningManager
class acts as a middle layer.
I was inspired by this Reddit post on structuring C# applications and followed common naming pattern described in the comments section (xxxHandler, xxxManager, xxxService).
The Commands/
directory contains all user-facing commands. Each command class implements ICommand
and is handled by CommandHandler
.
- CommandHandler.cs - parses user input and executes the corresponding command.
- ICommand.cs - Interface that all commands implement.
- Individual Commands - Each command (e.g. AddCommand, ListCommand, SnapshotCommand ...) handles a specific operation.
The Services/ directory contains core logic for version control.
- FileTracker.cs - Manages which files are tracked and their metadata.
- ListService.cs - Retrieves and formats snapshot history.
- SnapshotService.cs - Handles creating, storing, and retrieving snapshots.
- VersioningManager.cs - Serves as a middle layer, linking all services. Instead of command classes directly interacting with individual services. This provides uniform handling of versioning operations.
- Config.cs - Manages configuration settings, including the .versions directory path.
Program.cs
reads user input and passes it toCommandHandler
.CommandHandler
identifies the correct command based on the first argument.- The command class (e.g.
AddCommand
) executes, calling relevant Services via VersioningManager.
Unit tests are in simpleVersioningTests/
. They focus on Services, ensuring correct file tracking behavior, snapshot creation and restoration. Currently they only cover cases where user operates in initialized folder, not subdirectories of an initialized folder.
To run tests:
cd simpleVersioningTests
dotnet test