pvc <cmd>: patch version control command line utility.
NOTICE: pvc now works but will have bugs and the API is subject to change. Use at your own risk and always back up work that you are using pvc to track (aka use git and pvc together).

About

pvc is a version control system similar to git or mercurial, but is ultra simple: branches are simply a base followed by a set of unix patches with incrementing id. The only fundamental disadvantage (or advantage) of using pvc instead of git is that pvc supports only fast-forward merges, which are the cleanest and simplest to understand.

Basic Operation

The pvc command works very similar to git:
In the future civstack will offer tutorials for using all the development tools.

Initiaize your pvc repo

You may also want to see #git to use git for backups

With civ install .# you will have pvc installed.

To track an existing directory:

pvcignore

The .pvcignore file should contain a line-separated list of #string.find patterns that should be ignored. Items ending in / will apply to whole directories. A common pvc ignore file might look like:

# directories
%.git/
%.out/

# extensions
%.so$

# binary files
%./path/to/some_binary

Use with git

pvc is still in early development, so there is no hosting service which ergonomically supports backing-up development. The following is how pvc (and civstack) itself is developed and seems to work well.

Basically, we are going to have two git repositories. I will use civstack as the example:

First, put .pvc/ in your main repo's .gitignore

echo .pvc >> .gitignore

Second, follow the #init section above. This should include adding all your files to pvc and making your first pvc commit.

Third, cd .pvc/ and create your git repository inside the .pvc/ directory. This will literally track your patch files themselves. Use the following as your .pvc/.gitignore. You may also want to add a README.md directing folks to your main git repo.

# .pvc/.gitignore
**/*.snap/
backup/

Finally, add the following to your .bashrc

# Note: you must also have pvc aliased
function pvcp() {
  desc="$(pvc at): $(pvc desc --full)"
  (cd .pvc/ &&
    git add ./ &&
    git commit -am "$desc" &&
    git push origin main)
}

Now you can hack using pvc commit etc and push to your repo.pvc by simply calling pvcp. Your git commit log will be your current at location followed by the commit message. When you want to push your documentation or releases to git, simply do so -- your main commit log won't be polluted by commiting pvc files.

Architecture

This architecture is given both so users can debug or fix any errors as well as to make it easier to create other implementations of pvc (i.e. in bash).

pvc is composed of the following components:

Other Operations

Other operations, such as showing commit messages or ammending a commit, are not defined explicitly, but you can see the reference implementation for details. Typically their implementation is either straightforward or can be performed by variations of the above operations.

Also, operations which mutate the meaning of a commit (such as squash or rebase) should check to make sure that no branches depend on the branch being mutated.

Command pvc

Usage: pvc <subcmd> --help
This is the pvc command-line tool which can also be called directly from Lua.

Subcmd init

Usage: pvc init dir --branch=main
Initialize the current directory as a pvc directory. This will create .pvc/ and .pvcpaths Arguments:

Subcmd diff

Usage: pvc diff branch1=at branch2=local
Show the difference between two branches. The default is at (the current commit) vs local (the local working directory).

This command accepts either branch#id names or paths/to/dir/, where that dir/ has a .pvcpaths file. Arguments:

Subcmd commit

Usage: pvc commit -- my message
Commit local changes to the current branch, creating a new id.

If no message is given this uses the COMMIT file for the message, if it exists.

Subcmd at

Usage: pvc at branchId --hard
If branchId is not given, just returns current branch#id.

Otherwise, sets the active branch#id, causing the local directory to be updated to be that content. This will , this will fail (unless force=true) if it would cause any local changes to be overwritten.

at branch is called a "checkout" in other version control systems.
Arguments:

Subcmd tip

Usage: pvc tip [branch=current]
Get the tip id of branch.

Subcmd branch

Usage: pvc branch name [from=current]
Start new branch name branching off of from.

If from is a path/to/dir then it will graft those changes into the local repo as the named branch. (often used by maintainers to accept patches).

Subcmd show

Usage: pvc show [branch#id] --before=10
Show the commits before/after branch#id.

If branch#id is not given, print all branches. Arguments:

Subcmd desc

Usage: pvc desc branch#id=current [$to/new.cxt]
Get or set the description for a single branch id.

The new description can be passed via to/new.cxt or after -- (like commit).

Subcmd squash

Usage: pvc squash [name#id]
Combine changes and descriptions from branch id -> endId (inclusive) into a single commit. You can then edit the description using pvc desc branch#id.

This enables making lots of small commits and then "squashing" them into a single commit once they are in a good state. Arguments:

Subcmd rebase

Usage: rebase [branch=current] --id=10
Change the base of branch to id.

Rebase is a fundamental operation. It allows you to make or accept changes on your "main" branch while you work on development branches which are behind the main. See #basic for more details. Arguments:

Subcmd grow

Usage: grow --branch=current [from]
Copy changes in from onto branch.
In other version control systems this is called a "fast forward merge"
Arguments:

Subcmd prune

Usage: prune branch#id

Subcmd export

Usage: export branch to/
Copy all patch files in the branch to to/.
The resulting directory is commonly sent to tar -zcvf branch.tar.gz path/ and then branch.tar.gz sent to a maintainer to be merged.

Subcmd snap

Usage: snap [branch#id=current]
Get the snapshot directory of branch#id.

The snapshot contains a copy of files at that commit.

Types: Diff

Functions

Record Diff

Diff:of(dir1, dir2) returns what changed between two pvc dirs.

Fields:

Methods

Mod pvc.unix

Functions