safegit: Decentralised Git on Safe Network
by happybeing, 21 February 2019
This article explains how to create a decentralised git repository on Safe Network, push to it, clone from it, and submit pull requests back to it. So all the normal
git functionality is working, right now.
safegit is a script for creating and updating headless
git repositories on Safe Network using the Safe Command Line Interface (CLI).
This is an interim solution but achieves the aim of a truly decentralised alternative to github and other centralised solutions, based on the Safe Network. Once published, a project will be available to everyone forever as a secure immutable repository, without censorship, server downtime, or vulnerability to DDoS and other attacks.
It works by pushing to a local headless repository (repo) that is then published to Safe Network using the Safe CLI.
Setup and Workflow
Set Up (Linux)
- Install the Safe Command Line Interface (CLI).
- Get a copy of the safegit script. On Linux for example, clone the repo with:
cd ~/ git clone https://github.com/happybeing/safenetwork-git
- Set up an alias and make the script executable so you can run it by typing
safegit. For example if you use bash on Linux:
alias safegit='~/safenetwork-git/scripts/linux/safegit.sh' chmod +x ~/safenetwork-git/scripts/linux/safegit.sh
- You can see
safegitusage, including how to override the default location of your local headless repos by typing
safegitwithout any parameters. Do this now to check it is set up correctly.
You can now try out the following actions described in the sections below.
- Before you begin
- Create a local
- Publish/Update a git repo to Safe Network
- Update your
- Clone a git repo from Safe Network
- Issue a Pull Request after making changes
- Accept a Pull Request from someone else
Before you begin
Before you begin, log into your Safe Network account, or if you want to follow
along without affecting your real Safe Network account you can use a local test
network by typing
safe vault -t run-baby-fleming and then follow along exactly
In the following examples we'll assume you have a local project git repository in
~/src/dweb-blog. If you want to follow along, start out with:
mkdir -p ~/src cd ~/src git clone https://github.com/happybeing/dweb-blog
Create a local
Note: to follow along you'll need to use a different Safe NRS name from the one used in this example ('dgit'), because it is already taken. So choose your own and remember to use that wherever 'dgit' appears below.
1). Create a Safe NRS name and sub-name for your repository (repo) on Safe Network using the
Safe CLI. For example, for a local git based project in
~/src/dweb-blog you might create
dweb-blog.dgit as follows:
IMPORTANT: make sure to enclose the Safe XOR URI in double quotes and include
?v=0 at the end:
mkdir empty-directory safe files put -r empty-directory safe nrs create dweb-blog.dgit --link "<safe-xor-uri-from-files-put-command>?v=0" rm -r empty-directory
IMPORTANT: you must choose a Safe NRS name that you already own, or which is
free and not in use by somebody else. If you want to add a sub-name to a
safe NRS name which you already own, use
safe nrs add instead of
safe nrs create.
Alternatively, use the following short script which does the same as the above commands, but without you needing to copy and paste the URI and or '?v-0'.
mkdir -p empty-directory safe files put -r empty-directory | sed 's/^FilesContainer.*\"\(.*\)\"/\1/'| head -n 1 | sed 's/$/\?v=0/' | safe nrs create dweb-blog.dgit rm -r empty-directory
Note: In the above script, the
sed pipeline extracts the Safe XOR URI of the
FilesContainer from the output of
safe files put and formats it for use by
safe nrs create command.
Whatever Safe NRS name you choose becomes the
<repo-name> in the following examples (e.g.
dweb-blog.dgit). For multiple projects you can create multiple sub-names on the same NRS name, such as
2). Create a
safegit mirror for your local repository
We'll create a headless git repository to mirror your working repository (
~/src/dweb-blog) and link it to the Safe FilesContainer via the NRS URI
safe://dweb-blog.dgit that was set up in step 1.
Create a local mirror for
~/src/dweb-blog with the command.
cd ~/src/dweb-blog safegit create dweb-blog.dgit
The above creates a headless repo
dweb-blog.dgit and sets it up a remote in your project for it, called 'safegit'. You can see this with
git remote -v
$ cd ~/src/dweb-blog $ `safegit` create dweb-blog.dgit $ git remote -v origin https://github.com/happybeing/dweb-blog (fetch) origin https://github.com/happybeing/dweb-blog (push) safegit /home/mrh/src/safegit/dweb-blog.dgit (fetch) safegit /home/mrh/src/safegit/dweb-blog.dgit (push)
After making changes to your code you can push these to 'safegit' using normal
git commands, in the same way you would push to 'upstream' or 'origin' etc.
Publish/Update a git repo to Safe Network
Change to your working repository and push changes to the 'safegit' mirror:
cd ~/src/dweb-blog safegit push dweb-blog.dgit
This will upload or update the headless copy of ~/src/dweb-blog on Safe Network to match your local
safegit headless mirror. Headless means that the source files are not present, only the '.git' subdirectory.
You can review what has been uploaded using the
$ safe cat safe://dweb-blog.dgit
You can now publicise the existance of
safe://dweb-blog.dgit on Safe Network, a headless git mirror of your working repository
~/src/safegit/, but which is accessible to everyone.
safe://dweb-blog.dgit is not a website like github. It is a copy of the contents of your local
safegit remote repo
Every time you commit changes to 'master' and want to publish them you use
safegit push <repo-name>. For example:
safegit push dweb-blog.dgit
Any commits in master will be pushed to the headless mirror, and then to
Safe network and appear at
If you want to share other branches on your Safe repo (e.g. to submit a pull request back to a
safegit repo you cloned), you must first push them to the local
safegit repo. To push a branch to your local
git push safegit <branch>
You can now push everything to your Safe remote with
safegit push <repo-name> as we did for 'master'.
Clone a git repo from Safe Network
Anyone can make a copy of
safe files get -e overwrite safe://dweb-blog.dgit ~/headless-dweb-blog
To create a working repository, clone the headless copy using
git clone ~/headless-dweb-blog ~/working-dweb-blog
Changes to the new
~/working-dweb-blog can be published by creating a headless
safegit as explained above. Any changes to this 'fork' can be
pulled to other projects, including the original as described later.
The 'fork' will have remote 'origin' set to the local headless mirror. To pull updates from the original (
safe:/dweb-blog.dgit), update the local headless
copy and pulling them to the working repository. For example:
safe files get -e overwrite safe://dweb-blog.dgit ~/headless-dweb-blog cd ~/working-dweb-blog git pull
And finally, it's always worth checking the integrity of a cloned repository as follows (and you can add
--verbose to see more about what's going on):
$ git fsck --strict --unreachable Checking object directories: 100% (256/256), done.
Issue a Pull Request after making changes
A pull request works differently with
safegit than you are used to with github or similar git management websites. What follows is not the only way, but one suggested way that you can start with.
Make changes to a branch you create specifically for the pull request, having chosen a suitable name for the branch. For example, prefix the branch name with
<yourname>-pr-. So what we'll do it create a branch, push it locally, and publish to Safe Network.
The following example assumes we've already cloned
safe://dweb-blog.dgit and are working in our cloned project (e.g.
~/working-dweb-blog. It also assumes that we've already published our cloned repo to a remote at
safe://dweb-blog.tgit1, where 'tgit1' is a public name we created for our repos, and 'dweb-blog' the sub name for this particular project.
Changes we make can be shared using a pull request, as follows.
# Make sure you are up-to-date with the upstream repo safe files get -e overwrite safe://dweb-blog.dgit ~/headless-dweb-blog cd ~/working-dweb-blog git pull git checkout development # Your local working branch
Working on your local branch you commit some changes to the
README.md and decide you want to submit these changes
as a pull request.
Having checked your changes and when you're ready to create the pull request, make a branch for the pull request and check it out:
git branch pr-readme-changes git checkout pr-readme-changes # Push to your Safe Network remote safegit push dweb-blog.tgit1
Note: If you get a message like the one below, execute the suggested
git push command and then repeat the
safegit push (above):
fatal: The current branch pr-readme-changes has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream safegit pr-readme-changes
Generate a pull request message using the commit at which your
changes begin using a tag, or you can identify the hash using
git log which is what is being done here:
$ git request-pull 7b498aa5d9c8c81a36ada16603ac4a7c7c2bd8a8 safe://dweb-blog.tgit1 pr-readme-changes The following changes since commit 7b498aa5d9c8c81a36ada16603ac4a7c7c2bd8a8: Prevent wasteful renaming when deploying to safe (rsync -u -> cp -u) (2019-02-06 17:16:46 +0000) are available in the Git repository at: safe://dweb-blog.tgit1 pr-readme-changes for you to fetch changes up to 0c15476185831f51bfa0bdd8a973fee91992962b: Make improvements to README (2019-02-13 12:31:30 +0000) ---------------------------------------------------------------- theWebalyst (1): Make improvements to README README.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
We can now send the above in a message to the owner of
Accept a Pull Request from someone else
To accept a pull request means pulling a branch from a repo that has been published to Safe Network using
First you will make (or update) your headless copy of the 'foreign' repo which contains the pull request. Then you can pull it into a new branch on in the
original working repo
Example: if we receive a pull request from 'theWebalyst' (as in the output from
git request-pull shown above) we can pull those changes as follows.
# create or update our headless mirror of the 'foreign' repo safe files get -e overwrite safe://dweb-blog.tgit1 ~/headless-foreign-dweb-blog # create a branch to receive the changes (so they aren't merged immediately) cd ~/src/dweb-blog git branch pr-readme-changes git checkout pr-readme-changes # pull the changes into the new branch, in original author's working repo git pull ~/headless-foreign-dweb-blog pr-readme-changes
We now have the changes on branch 'pr-readme-changes' which we can review and decide whether to merge into master.
Update 1st July 2020
This article was updated to use the Safe CLI in place of Safe Drive which no longer works due to changes to the Safe Network APIs.