// Copyright © 2023 Kim Altintop <kim@eagain.io>
// SPDX-License-Identifier: CC-BY-SA-4.0

= Getting started with _it_
:stylesheet: monospace.css
:source-highlighter: pygments

This document walks you through the very basics of _it_. Many of the
interactions below may be automated away eventually, but our goal here is to
provide an overview of what is going on under the hood.


== Prerequisites

We are going to assume you have the _it_ executable installed using

    cargo install --git https://git.eagain.io/it

Chances are that you already have an SSH key handy. If not, or if you want to
use a key specifically for this exercise, generate one using

    ssh-keygen -t ed25519

It is also a good idea to add this key to your `ssh-agent`, so you don't have to
type the password every time it is used for signing. Typing `ssh-add` usually
does the trick.

Next, we'll need to teach git to use our SSH key for signing. If you followed
above recommendation and are using an agent for signing, the following commands
will set it up as a default:

    git config --global gpg.format ssh
    git config --global user.signingKey "key::$(cat /path/to/your_key.pub)"

If you prefer to not mess with your existing git configuration, you can also
arrange for the key to be recognised by _it_ itself by running the following
command instead:

    git config --global it.signingKey "key::$(cat /path/to/your_key.pub)"

Lastly, we'll create an _it_ xref:spec.adoc#_identities[identity] using this
key:

    it id init

The command's output will look similar to this:

[source,json]
----
{
  "committed": {
    "repo": "~/.local/share/it/ids",
    "ref": "refs/heads/it/ids/671e27d4cce92f747106c7da90bcc2be7072909afa304d008eb8ecbfdebfbfe2",
    "commit": "e08c34df95cd28aa212a4d110ecfb8acec2a102c"
  },
  "data": {
    "signed": {
      "_type": "eagain.io/it/identity",
      "spec_version": "0.1.0",
      "prev": null,
      "keys": [
        "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDtt6XEdNVInhiKkX+ccN++Bk8kccdP6SeBPg0Aq8XFo"
      ],
      "threshold": 1,
      "mirrors": [],
      "expires": null,
      "custom": {}
    },
    "signatures": {
      "ddc27a697903b8fe3ae3439818af81eaac20ba65e51a4170e3c81eb25abd1767": "5a460b26099ddd42912b7a52ee0c478619425ddfe4a562fd2ffd427d84cde6ab32effd8971308cfcdb64b08ac920e7a2c2a69d11b0ca7fe293e39306cd4d7c01"
    }
  }
}
----

The `data` object is exactly what is stored in the repository `repo` at branch
`ref`, which we invite you to convince yourself of using normal git commands.

Identities can describe multiple keys, and carry additional custom metadata, but
we'll skip over this for now.


== Local drop

_it_ is organised around patches. You know, like in the olden days, but
xref:spec.adoc#_patches[not quite]. Patches are recorded onto a log dubbed
xref:spec.adoc#_drops["`drop`"].

If you have a git repository to toy around with, you can initialise a drop
adjacent to the "normal" branches in it. You can record patches (which you may
have received from elsewhere) onto that local drop, and push it to wherever you
like.

To initialise a drop in this way, just run:

    it drop init --description "my project"

This will drop you into `$EDITOR` to give you an opportunity to customise the
drop's metadata, which will look similar to this:

[source,json]
----
{
  "description": "my project",
  "roles": {
    "drop": {
      "ids": [
        "671e27d4cce92f747106c7da90bcc2be7072909afa304d008eb8ecbfdebfbfe2"
      ],
      "threshold": 1
    },
    "snapshot": {
      "ids": [
        "671e27d4cce92f747106c7da90bcc2be7072909afa304d008eb8ecbfdebfbfe2"
      ],
      "threshold": 1
    },
    "mirrors": {
      "ids": [
        "671e27d4cce92f747106c7da90bcc2be7072909afa304d008eb8ecbfdebfbfe2"
      ],
      "threshold": 1
    },
    "branches": {
      "refs/heads/main": {
        "ids": [
          "671e27d4cce92f747106c7da90bcc2be7072909afa304d008eb8ecbfdebfbfe2"
        ],
        "threshold": 1,
        "description": "the default branch"
      }
    }
  },
  "custom": {}
}
----

You may want to check if _it_ has guessed your mainline branch correctly (in the
`branches` section), but otherwise just save and exit to finish the
initialisation step. Run

    git log -p refs/it/patches

to see the effect.


We want source code patches to be against the `refs/heads/main` branch, so we
need to teach the drop about what the current state is:

    it merge-point record

Again, you may want to run `git log` as above to see what changed. You'll notice
a line starting with "Re:" in the latest commit message: this is the
xref:spec.adoc#_topics[topic] of a patch, and a xref:spec.adoc#mergepoints[merge
point] is just a patch with a well-known topic. Run

    it topic ls

to see that this topic now exists, and

    it topic show c44c20434bfdaa0384b67d48d6c3bb36d755b87576027671f606c404b09d9774

to display the metadata recorded in it.

Whenever you update `refs/heads/main`, run `merge-point record` again to convey
the new head to the drop. ``show``ing the topic as above will give you a log of
every such update.


Finally, let's create a patch: make some changes on a feature branch, like you
normally would, and then run

    it patch record

This will drop you into `$EDITOR`, asking you to describe what the patch is
about. After you save and exit, a new record will be committed onto the drop,
and a new topic will have been created:

    $ it topic ls
    {
      "topic": "2d2d3c97df62b18d3d1476342fe9d6df0989592f6d55d151350422795da714d8",
      "subject": "Just testin"
    }
    {
      "topic": "c44c20434bfdaa0384b67d48d6c3bb36d755b87576027671f606c404b09d9774",
      "subject": "Merges"
    }

You can post more patches to an existing topic, and reply to a specific entry
within the topic. Because a patch in _it_ is really a combination of commentary
and source code changes, and source code changes are actually optional, we have
a handy shortcut to just, well, comment:

    it topic comment record 2d2d3c97df62b18d3d1476342fe9d6df0989592f6d55d151350422795da714d8

Type your comment into `$EDITOR`, save and exit. The result may look like this:

    $ it topic show 2d2d3c97df62b18d3d1476342fe9d6df0989592f6d55d151350422795da714d8
    {
      "header": {
        "id": "11337eb409fbd16a034d0323dfa8d879b5a0f36c",
        "author": {
          "name": "Kim Altintop",
          "email": "kim@eagain.io"
        },
        "time": "2023-01-09T09:39:15+01:00",
        "patch": {
          "id": "8da0f98009aae98e7ca9df926125aa386a4f6a644c2036e9ec86a0810a7b8a62",
          "tips": []
        },
        "in-reply-to": "0c9b7c0b437a3a072f3a1eead17703d22a0bf8f1"
      },
      "message": {
        "_type": "eagain.io/it/notes/basic",
        "message": "Ship it"
      }
    }
    {
      "header": {
        "id": "0c9b7c0b437a3a072f3a1eead17703d22a0bf8f1",
        "author": {
          "name": "Kim Altintop",
          "email": "kim@eagain.io"
        },
        "time": "2023-01-09T09:23:51+01:00",
        "patch": {
          "id": "502b3c4dcf709c9b16df2b58aece9a8966405347a2bf6ccbb305711120984951",
          "tips": [
            "refs/it/bundles/502b3c4dcf709c9b16df2b58aece9a8966405347a2bf6ccbb305711120984951/heads/main"
          ]
        }
      },
      "message": {
        "_type": "eagain.io/it/notes/basic",
        "message": "Just testin"
      }
    }


Notice the `patch.tips` array? If the patch contains references which are
conventionally recognised as source code changes (i.e. `refs/heads/...`,
`refs/tags/...`), their physical location inside the drop's repository will be
shown here. _it_ is currently lacking a nice UI for this, but you can just do

    git diff refs/it/bundles/502b3c4dcf709c9b16df2b58aece9a8966405347a2bf6ccbb305711120984951/heads/main

to see the diff against your currently checked-out branch. If you're satisfied,
go ahead and merge this ref into your local `main` branch. Don't forget to thank
yourself for the contribution by commenting on the topic!


To wrap it up, you may be wondering how _it_ stored everything in your
repository, and perhaps clean it up. Run

    git for-each-ref refs/it

to poke around the references _it_ uses to maintain its state. Note, however,
that this structure is not part of any public API, and may change without
further notice!

The actual xref:spec.adoc#_bundles[patch bundles] can be found in
`.git/it/bundles`. Note that a patch bundle is self-contained -- you can send
them over email, store them in IPFS, or whatever is convenient to move them from
one place to another.


== Remote drop

We said that you could receive patches over whatever channel, and apply them to
your local drop. A more tangible way is to serve the drop over HTTP, allowing
anyone to submit patches to it. While it's possible to do this from your working
repository, it is preferable to create a dedicated repo for the drop:

    it drop init --git-dir /the/drop.git --description "my public drop"
    it merge-point record --git-dir /the/drop.git --source-dir .
    cd /the/drop.git
    RUST_LOG=debug it serve

In a second terminal, cd into your working repo and add the drop as a regular
git remote:

    git remote add dropit /the/drop.git
    git remote update dropit

You can now submit to it by replacing `record` with `submit` for the respective
commands, and specifying `--drop dropit/patches` to use the remote drop as the
reference.

Currently, an extra command `it drop bundles sync` is needed to receive the
patch bundles after updating the remote. This is not particularly smart yet,
especially given that we do support inspecting individual topics (as
opposed to the entire drop history) by `it topic unbundle`. We'll get there.


== Loose ends

If you've used email to send around patches, or even the excellent
https://git.kernel.org/pub/scm/utils/b4/b4.git[b4] tool, this may all seem
vaguely familiar to you: instead of `mbox` archives we have binary git bundles,
what gives?

That's fair, we haven't really detailed how _it_ permits much richer
interactions and datatypes, for lack of a UI. For brevity, we also haven't shown
that patch bundles can be stored on IPFS, the "commit bit" can be extended to
co-maintainers, or how more complex topologies can be created by drop
aggregation (and without resorting to HTTP POST).

We invite you to play around with the available commands, read the
xref:spec.adoc[spec], and perhaps consider to contribute where you see _it_ is
currently lacking :)
