Projects in a space

Add your GitHub repos as projects, connect them to a space at a branch, tag or commit, and install, update and sync them with your own git.

A project is a GitHub repo: one of yours, or any public one, such as Flask or Express. A space holds projects, each at a ref (a branch, tag or commit), so anyone who installs the space gets the same checkouts. xo keeps both lists in your XO account; the clones are on your machine.

Add a project

xo create project https://github.com/pallets/flask       # cloned into ./flask
xo create project https://github.com/expressjs/express   # cloned into ./express
xo create project notes                                  # no GitHub remote: ./notes, git init
xo projects                                              # your projects

A GitHub project is called by its repo's name, flask, in every command. When two of your projects share that name, such as a fork and its upstream, call it by OWNER/REPO; its folder is then ./OWNER/REPO.

A project made from a plain name can get its repo later:

xo connect notes --repo https://github.com/OWNER/REPO

It is called REPO from then on, and ./notes gets that origin if it has none and moves to ./REPO.

Put it in a space

xo connect web                          # a new space entry, web, with no XO Cloud space
xo connect flask web --ref main         # Flask in the space web, at main
xo connect express web --ref v5.1.0     # Express in it too, at its tag v5.1.0
xo connect old --id THE_ID              # an entry for an XO Cloud space you already have
xo spaces                               # your spaces, with their projects and refs
xo list                                 # your projects and your spaces together

xo works out which name is the project and which the space, so xo connect web flask works too. For a space named like one of your projects, say space:NAME; project: and space: work in front of any name.

A project you have not added yet

xo connect https://github.com/psf/requests web   # adds Requests, then puts it in web
xo install space:web                             # clones each project into ./web/REPO

xo connect PROJECT SPACE adds a project that is not in your projects yet, as xo create project does but without making its folder, then puts it in the space, and says so.

  • Give the project as OWNER/REPO or a GitHub URL. A plain name becomes a project with no repo, which xo connect NAME --repo URL can give one later.
  • Nothing is added when the space is missing. If the space then refuses the project (it is full, say), the project stays in your projects.
  • A plain name close to one of your projects, most likely a typo, is refused with the name it is close to, since xo cannot delete a project. To add it anyway, say project:NAME.
  • Put a new plain name first. xo connect web notes is refused when web is one of your spaces, since notes could be a space you have not made yet: say xo connect project:notes space:web, which adds notes as you typed it. OWNER/REPO and a URL work in either order.

If the first command above stops with connect what? or invalid choice, your xo is older than this: update it.

Install, update and sync

xo install space:web    # ./web/REPO for each project, at its ref
xo update space:web     # push each branch with new commits under ./web, then record the refs
xo sync space:web       # rebase and push each branch, merge the space's refs, record

The same three work on one project: xo install project:flask clones it here (or fetches and fast-forwards it), xo update project:flask pushes its branch, and xo sync project:flask runs git pull --rebase, then pushes.

  • update and sync push only branches with new commits, so a repo you can't push to is no problem until you commit to it. Without the quirq hub (below) they push to GitHub, so they need push access there. For a repo you can't push to, such as Flask, put your fork in the space in place of Flask (xo connect YOU/flask web) and push to that. Kept beside Flask, the two are called pallets/flask and YOU/flask, and the space installs them in ./web/pallets/flask and ./web/YOU/flask.

  • They use your own git and its login, over https, without submodules. ./SPACE/.xo/state.json remembers what was installed.

  • update is refused when the remote is ahead or the space changed since you installed it: run xo sync. A ref its remote does not have is refused too, so nobody else's install breaks.

  • sync keeps your changes and the space's. If both changed the same project, it stops and changes nothing. If git cannot rebase a branch cleanly, xo undoes the rebase and says so.

xo never touches a checkout with uncommitted changes, never forces a push, and refuses a folder whose origin is another repository or carries a login (https://USER@github.com/...).

Through the quirq hub

Once xo login found the quirq hub, a space's GitHub projects work through it: the hub is a relay for you and your agents while the work is under way, and GitHub stays where the work ends up.

  • Each checkout gets a second remote, quirq, quirq://hub.quirq.dev/AGENT/OWNER--REPO. origin and everything GitHub sees stay as they are, so git push and pull requests work as before.
  • install also fetches the hub, and takes a branch from there when the hub has it.
  • update pushes each branch with new commits to the hub, never to GitHub, so Flask needs no fork here. sync rebases on the hub's branch first. Push to GitHub yourself (git push, a pull request) when the work is done.
  • Anyone can read the hub in this version, so a project GitHub does not show to everyone is refused before anything is sent.
  • sync never rewrites a commit GitHub already has: when your branch and the hub's have both moved on and yours holds commits on GitHub, it stops and asks you to merge the hub's in by hand.
  • project:P commands stay on GitHub. If the hub's client goes missing after xo login, a space's update and sync stop and say how to install it.

Next: share a space or a project.