Got /

Game of Trees

Game of Trees (Got) is a simple, easy to use version control system that aims to be compatible with git repos.

It's still under development, but can be used today as a substitute for git. It is freely reusable under a BSD license.

Install

$ doas pkg_add got

Configuring got

First, we need to tell got about the author of the repo:

$ export GOT_AUTHOR="username <username@example.com>"

Replace username and username@example.com. It's recommended to add this as part of your ~/.profile?:

$ echo 'export GOT_AUTHOR="username <username@example.com>"' >> ~/.profile

Let's also enable tab-completion of got commands:

$ echo 'set -A complete_got_1 -- $(got -h 2>&1 | sed -n s/commands://p)' >> ~/.profile

By default, got uses the text editor ed if $EDITOR? or $VISUAL? are not set.

Clone a repository

To clone a repo without encryption (WARNING: insecure):

$ got clone git://example.com/repo.git

Replace example.com/repo.git with your actual path.

For this guide, we will use the ngircd git repo as an example:

$ cd ~
$ got clone git://github.com/ngircd/ngircd

To clone a repo using ssh:

$ got clone ssh://example.com/repo.git

For example, to clone OpenBSD's github repo:

$ cd /var/git/
$ got clone ssh://git@github.com/openbsd/src.git

HTTP URLs currently requires git?:

$ git clone https://github.com/ngircd/ngircd

Checkout code

Once you have a repository, you must first checkout the code into a work tree before you can use it:

$ got checkout /path/to/repository

Replace /path/to/respository.

Let's checkout the ngircd code:

$ cd ~
$ got checkout ~/ngircd.git

You can check out code from a specific branch or commit with -b and -c:

$ got checkout -b branch -c commit /path/to/repository

got creates an ID SHA1 hash for every commit, so replace commit with that hash.

Before we can checkout another work tree from ngircd, we must delete the old one:

$ rm -r ~/ngircd
$ got checkout -b HEAD -c f4ade537d550b872b7e86e6ffce940dfbad4c60c ~/ngircd.git

This will first delete the old work tree, then check out the f4ade537d550b872b7e86e6ffce940dfbad4c60c commit from HEAD of the ngircd.git repo.

got checkout will show these status codes:

StatusMeaning
Anew file added
Efile already exists

For the next step, we will go ahead and delete this work tree, then check out a work tree based on the most recent commit:

$ rm -r ~/ngircd
$ got checkout ~/ngircd.git

Create a new repository

To create an empty repository:

$ got init /path/to/repository

Replace /path/to/repository. For example:

$ got init ~/ircnowd.git

This will create a got repo called ircnowd.

Afterwards, we need to import the code for the repository:

$ got import -m "Import sources" -r /path/to/repository /path/to/code
  • -m provides the log message for the import.
  • -r provides the repository path.

Replace /path/to/repository and /path/to/code. For example:

$ got import -m "Import sources" -r ~/ircnowd.git ~/ngircd

This will import the code from ngircd into ircnowd.git.

Fetch new changes

To fetch changes from a remote repo:

$ got fetch

Add file

To add an unversioned file for the next commit:

$ got add filename

Replace filename. For example:

$ echo 'print "hello, world"' > ~/ngircd.git/hello.sh
$ got add ~/ngircd.git/hello.sh

If adding a directory:

$ got add -R pathname

-R allows recursion. Replace pathname.

Let's add a directory with a file inside ngircd.git, then begin tracking the directory with got:

$ mkdir -p ~/ngircd.git/newcode/
$ echo 'print "IRCNow and Forever"' > ~/ngircd.git/newcode/ircnow.sh
$ got add -R ~/ngircd.git/newcode

Remove file

To remove a versioned file for deletion from the repo in the next commit:

$ got remove filename

Replace filename.

Let's remove hello.sh:

$ got remove ~/ngircd.git/hello.sh

If removing a directory:

$ got remove -R pathname

-R allows recursion. Replace pathname.

Let's remove the newcode directory:

$ got remove -R ~/ngircd.git/newcode/

View changes

To view changes in a work tree:

$ got diff

If you provide two objects, got will show the diff between just those two:

$ got diff object1 object2

Replace object1 and object with the ID SHA1 hash. For example:

$ got diff ab0eb099e9c0ed60d25fb50dd78d2a638d3b49b8 f4ade537d550b872b7e86e6ffce940dfbad4c60c

This will give you the diff of two files with those ID hashes.

Blame

For a line-by-line history of a file:

$ got blame /path/to/file

Use -c commit and replace committ with the ID SHA1 hash to start history from that specific commit. For example:

$ cd ~/ngircd
$ got blame -c 71ae2b7d ~/ngircd/NEWS

Update

To update the work tree to the most recent commit on the work tree's branch:

$ got update

This will require manual merging of files if there are conflicts.

StatusMeaning
Ufile updated, no local changes
Gfile updated, local changes merged
Cfile updated, conflicts occurred during merge
Dfile deleted
Anew file added
~versioned file blocked by non-regular file
!missing versioned file restored
#file not updated due to merge conflicts
?changes for an unversioned file not merged

NOTE: If there are staged changes, you must first commit or unstage them before using got update.

Suppose we check out a specific commit:

$ cd ~
$ rm -r ngircd
$ got checkout -b HEAD -c f4ade537d550b872b7e86e6ffce940dfbad4c60c ~/ngircd.git

We can then update a specific commit:

$ got update -c c8b12af1d2d155ec79dc2044a4ff177cf07de4fe

View status

To view the status of files in a work tree:

$ got status
StatusMeaning
Mmodified
Aadded in next commit
Ddeleted in next commit
Cmodified or added but contains merge conflicts
!versioned file expected but missing
~versioned file blocked by non-regular file
?unversioned item, not tracked

If changes are staged, the second column uses these codes:

StatusMeaning
Mmodification staged
Aaddition staged
Ddeletion staged

Show History

To show commit history:

$ got log

This will produce a log of all commits from the current branch:

...
-----------------------------------------------
commit ab0eb099e9c0ed60d25fb50dd78d2a638d3b49b8
from: Alexander Barton <alex@barton.de>
date: Tue Dec 11 22:04:21 2001 UTC

 - Test auf stdint.h (HAVE_STDINT_H) hinzugefuegt.

-----------------------------------------------
commit f4ade537d550b872b7e86e6ffce940dfbad4c60c
from: Alexander Barton <alex@barton.de>
date: Tue Dec 11 21:53:04 2001 UTC

 Initial revision

To display commits from other branches -b, starting at a specific commit -c, limited by the number of commits -l:

$ got log -b -c commit -l N

Replace commit with the ID SHA1 hash and N with the number of commits.

For example:

$ got log -b -c 71ae2b7d7f9ae7bc02ed072c07100de0027373d6 -l 10
-----------------------------------------------
commit 71ae2b7d7f9ae7bc02ed072c07100de0027373d6 (master, origin/master, tags/rel-26.1)
from: Alexander Barton <alex@barton.de>
date: Sat Jan  2 13:32:48 2021 UTC

 ngIRCd Release 26.1
...

It's also possible to show commits that match a regular expressions:

$ got log -s regex

Replace regex with a regular expression:

$ got log -s ssl
-----------------------------------------------
commit daa88b765111b14047c97256bd2a9a2daabe123b
from: Christoph Biedl <ngircd.anoy@manchmal.in-ulm.de>
date: Mon Dec  5 22:51:07 2016 UTC
via: Alexander Barton <alex@barton.de>

 Fix building ngIRCd with OpenSSL 1.1
...

Branching

To print the name of the current branch of the work tree:

$ cd /path/to/worktree
$ got branch

To list all the branches:

$ got branch -l

Inside a work tree, you can create a branch and switch to it:

$ got branch branchname

Replace branchname.

You can also delete a branch:

$ got branch -d branchename

Only the branch reference branchname is deleted; commit, tree, and blob objects remain in the repo.

To branch at a specific commit:

$ got branch -c commit branchname

Replace commit with the ID SHA1 hash and replace branchname. For example:

$ got branch -c 02850008f4a4e8fff5799157d21ee7924345b3e1 gnutls

This creates the gnutls branch of ngircd.

Tags

To list all existing tags:

$ got tag -l

To create a tag pointing to the most recent commit:

$ got tag -m "Message" tagname

Replace tagname and Message.

To create a tag pointing to a specific commit:

$ got tag -c commit -m "Message" tagname

Replace commit with the ID SHA1 hash and replace Message and tagname. For example:

$ got tag -c 3c627dd70d032fa2c5087617da27586cf85e899a -m "Debian OpenSSL Build" debopenssl

This will create the debopenssl tag to point to commit 3c627dd70d032fa2c5087617da27586cf85e899a.

Revert changes

If you make any changes to files or folders in a work tree, you can revert those changes:

WARNING: There is no way to undo reverted changes!

$ got revert /path/to/file

Replace /path/to/file. Files added with got add become unversioned, and files deleted with got remove are restored.

To be safe, use -p so that got asks before reverting. You can also add -R for recursion:

$ got revert -R -p /path/to/folder

For example:

$ cd ~/ngircd
$ mkdir JUNK
$ echo "Here is some new junk" > JUNK/INFO
$ got add -R JUNK/
$ got revert -R -p JUNK/

Commit

To commit changes in a work tree:

$ got -m "Commit message" commit

Replace Commit message with a commit message.

If changes have been staged, only staged changes will be committed.

StatusMeaning
Mmodified file
Dfile deleted
Anew file added

NOTE: If changes are not based on the most recent commit, you may first be required to run got update before commits can be made.

NOTE: Before running got commit, make sure to set up the GOT_AUTHOR environment variable (see above).

Send Changes

To send changes to a remote repo:

$ got send -r ssh://path.com/to/repo

Replace ssh://path.com/to/repo with the protocol and URL.

By default, if no remote repo is provided, the work tree's origin (its default repo) will be used.

Changes are only be sent if they are based on up-to-date branches in the remote repo. If not, new changes must first be fetched with got fetch and local branches must be rebased with got rebase. -f ignores this requirement.

WARNING: Try to avoid -f because it may result in inconsistent tags in different repos.

To send all branches:

$ got send -r ssh://path.com/to/repo -a

Replace path.com/to/repo. To specify a specific branch:

$ got send -r ssh://path.com/to/repo -b branchname

Replace branchname. To delete a branch (only references are deleted):

$ got send -r ssh://path.com/to/repo -d branchname

Rebase

When you have multiple branches, you may want to rebase the commits of one branch onto your current branch:

$ got rebase branchname

Replace branchname. Note that branchname must have a common ancestor with the current branch.

Commits from branchname are made to the work tree's current branch.

To show a list of past rebases:

$ got rebase -l

Staging

To stage for the next commit:

$ got stage

To stage just one file:

$ got stage /path/to/file

stage [-l] [-p] [-F response-script] [-S] [path ...]

StatusMeaning
Aaddition staged
Mmodification staged
Ddeletion staged

If there are staged changes, got commit will not commit any paths that do not have staged changes.

To list staged changes:

$ got stage -l

If a file is out of date compared with the work tree's current branch, you must run got update before staging.

To unstage all changes:

$ got unstage

To unstage a single file:

$ got unstage /path/to/file

Info

To show metadata about a work tree:

$ got info

To show additional data about a file:

$ got info /path/to/file