Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions 34.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
NIP-34
======

`git` stuff
-----------

`draft` `optional`

This NIP defines all the ways code collaboration using and adjacent to [`git`](https://git-scm.com/) can be done using Nostr.

## Repository announcements

Git repositories are hosted in Git-enabled servers, but their existence can be announced using Nostr events, as well as their willingness to receive patches, bug reports and comments in general.

```jsonc
{
"kind": 30617,
"content": "",
"tags": [
["d", "<repo-id>"],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A word on this, please. I can't find a repo-id definition

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just an arbitrary string, as in all other d tags.

Copy link
Copy Markdown
Member

@Giszmo Giszmo Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make sense to prescribe this? If we used the initial commit hash for example, finding/detecting forks would be easier. fiatjaf:30617:helloWorld might be a very different repo than giszmo:30617:helloWorld but giszmo:30617:<sha256-of-bitcoin-root-commit> ... would hopefully match between all forks.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea a lot - something github doesn't do and we could - that allows people to find all the forks. But this particular event contains data that would differ between forks.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it too, but how can you be sure? Maybe we can have another single-letter tag for this that only interested implementations would include, to prevent others from having to check invalid data.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some OSS products which fork has become the official developer because the original author retired the development.

https://github.com/ctrlpvim/ctrlp.vim

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make it the root commit id? For forks it could be the id of the earliest unique commit. The repository COULD contain a config file which specifies this id so that clients MAY access the config to automatically identify the correct id.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
["d", "<repo-id>"],
["d", "<repo-id>"], // the earliest unique commit id. usually the root commit id unless it's a fork.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this enables clients with access to the local repo to find repo events for it. It is also resilient to name changes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alternatively, the following could be added.

    ["r", "<repository-unique-reference>"], // the earliest unique commit id. usually the root commit id unless it's a fork.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if I have two projects with the same root commit id?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then there is a fork and the earliest unique commit id should be used instead. the repo event should contain a ["r","[commit-id]"] outlining this so the contributor doesn't need to identify it.

Clients could make more sense of this if, in the case of a fork, 2 tags are used as follows:

Suggested change
["d", "<repo-id>"],
["d", "<repo-id>"], // the earliest unique commit id. usually the root commit id unless it's a fork.
["r", "<repo-id>"],
["r", "<first-commit-id>"], // if the first commit id isn't the earliest unique commit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me, but I think we should leave d as an arbitrary string and use r for the root/fork git commit identifiers.

["name", "<human-readable project name>"],
["description", "brief human-readable project description>"],
["web", "<url for browsing>", ...], // a webpage url, if the git server being used provides such a thing
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this could document all you could use directly for mailto URI email address.
emails still widely used for project like linux.
also a fall-back if the list of original relay is perm down.

["clone", "<url for git-cloning>", ...], // a url to be given to `git clone` so anyone can clone it
["relays", "<relay-url>", ...] // relays that this repository will monitor for patches and issues
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is missing some timestamp / expiry notion.
you can have collaborative codes contributions spawning years on some project.
that ways can be used for policy migration if you wish to update repo-id / relays / root.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all nostr events must include a created_at timestamp.
any nostr event with a kind in the 30000-40000 range is a 'parameterized replaceable event'. This means all metadata apart from the pubkey and d tag can be updated by issuing a new event with a larger timestamp.
a deletion event (nip09) would indicate the repository event has expired

]
}
```

The tags `web`, `clone`, `relays` can have multiple values.

Except `d`, all tags are optional.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you can recommend d to be a 80-bit / 128-bit random string.
that way minimize collision at the relay level
there is name for human-readable label.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using human readable d identifiers follows a precedent established outside of nip34.
replaceable events are referenced with <kind>:<pubkey>:<identifier> so the collision problem is limited to repo events issued by the same pubkey.
The r tag with a euc marker (earliest unique commit) can also be used to identify the repository.


## Patches
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do you send a patch series?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it simpler to send a pull request?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know? How do people normally do it in git send-email? I know you can send multiple patches in the same email and you could do the same in the Nostr event. Then when applying with git am -i <patch> it works fine.

Or you could send multiple events? I'm not sure what is the best flow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git send-email sends multiple emails when you give it multiple patches. it creates a proper email thread so that you can reply to each patch individually. the nostr equivalent would be building a nip-10 thread of patches.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it simpler to send a pull request?

this implies you have write access to the repo in question, or that you have a hosted fork somewhere. it is much easier to just send patches as it requires no hosting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about a pull request event which patches tag? later updates based on feedback or rebases could also be associated with the same pull request.


Patches can be sent by anyone to any repository. Patches to a specific repository SHOULD be sent to the relays specified in that repository's announcement event's `"relays"` tag. Patch events SHOULD include an `a` tag pointing to that repository's announcement address.

```jsonc
{
"kind": 1617,
"content": "<patch>", // contents of <git format-patch>
Comment thread
Giszmo marked this conversation as resolved.
"tags": [
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
Copy link
Copy Markdown
Contributor

@jb55 jb55 Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we probably also want a "version" tag. patches tend to have more than one version git format-patch -v2, -v3, etc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean lots of this stuff already shows up in the patch itself, so not sure if worth it. but just something to consider.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>", "<relay-url>"],
["r", "<repository-unique-reference>"], // the earliest unique commit id. usually the root commit id unless it's a fork.

This associates the patch with the git repository. If the maintainer changes (or if there are multiple), clients can easily query relays for all patch.
also adds relay hint to a

["p", "<repository-owner>"],
Comment thread
fiatjaf marked this conversation as resolved.
["p", "<other-user>"], // optionally send the patch to another user to bring it to their attention
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can say a default limit (e.g 20’s other-user).
relays can have local policy saying they allow more.
or price them with zaps or other micro-payments.
otherwise amplification attack vector for relay.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

events that tag large numbers of pubkeys or events can be identified as spam either at the relay level or by clients.
I'm not sure there needs to be a default limit as other spam identification criteria can be used such as web of trust, reports, etc.


// for the first patch in a thread or series
["t", "root"],

// optional tags for when it is desirable that the merged patch has a stable commit id
// these fields are necessary for ensuring that the commit resulting from applying a patch
// has the same id as it had in the proposer's machine -- all these tags can be omitted
// if the maintainer doesn't care about these things
["commit", "<current-commit-id>"],
["parent-commit", "<parent-commit-id>"],
["commit-pgp-sig", "-----BEGIN PGP SIGNATURE-----..."], // empty string for unsigned commit
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

often on projects like linux, you can have commit signed by multiple authors / contributors.
so i think “commit-pgp-sig” + “committer” could be option duplicated.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an interesting idea. git only supports a single pgp signature which in the git-over-email model is the committer rather than the author(s).
The main purpose of retaining the pgp signature is to retain the original commit id.
Including more than one pgp signature and committer would make it unclear which should be used to create the commit id.
What would be the value of including additional pgp signatures when git can't interpret them and all patches / responses are in signed nostr events?

["committer", "<name>", "<email>", "<timestamp>", "<timezone offset in minutes>"],
]
Comment thread
fiatjaf marked this conversation as resolved.
Copy link
Copy Markdown
Contributor

@DanConwayDev DanConwayDev Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
]
// if first patch in patch set with no cover_letter
["t", "root"], // if first version
["t", "root-version"], // if first additional version
["e", "<id-of-root-of-previous-version", "mention"], // if first additional version
// else
["e", "<id-of-root-patch-or-cover-letter", "root"], // this may be a root-version
["e", "<id-of-[previous-patch-in-set]-or-for-first-[cover-letter]", "reply"],
]

reflecting proposal in #997 (comment)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by these quotes, "["root"]?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of writing all these e tags in the example we should just say these events should follow NIP-10 threading rules. It will be less confusing for people reading.

Now about the t tags I don't think they help. If a human is reading a list of patches or a thread with multiple patches and comments they will be able to see which patches are roots and which ones are v2, v3 and so, either from the context or from something written in the patch title. And if a machine is reading it or if someone wants to refer to a patch with absolute precision they should use the Nostr event id.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by these quotes, "["root"]?

typo fixed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of writing all these e tags in the example we should just say these events should follow NIP-10 threading rules. It will be less confusing for people reading.

I agree that what I wrote is confusing regarding threading however, its not clear how NIP-10 threading rules should be applied. Should the third patch in the set 'reply' to the second? a naive reading of the rules may suggest not unless it directly uses the change, but clients shouldn't be expected to automatically detect this. I think we this nip should clarify, for both consistency and as the decision effects comparability with the PR model.

The problem trying to be solved by stating that patches should reply to the previous patch in the PR model is as follows:
Assuming the commit id's cannot be replied upon, how can a client know if the patch is a intended to be used in combination with, or replace, another patch?

typo-PR-model

without the reply mechanism the typo fix 'amended' commit could be seen as a descendant, instead of a replacement by a client. Of course a human would see it, but we want clients to detect this and provide a smooth user experience.

Now about the t tags I don't think they help. If a human is reading a list of patches or a thread with multiple patches and comments they will be able to see which patches are roots and which ones are v2, v3 and so, either from the context or from something written in the patch title. And if a machine is reading it or if someone wants to refer to a patch with absolute precision they should use the Nostr event id.

Here is the problem this is trying to solve: as a client I want to create a single subscription to return the only the root event of proposed changes so that I can display their titles as a list.

I suppose it is not too much of a problem to get all versions of proposed changes and filter them client side by filtering those that 'mention' other proposed changes. This would remove the root-version tag.

How else could this be achieved without the ["t","root"] tag or requesting every patch?

}
```

## Issues

Issues are Markdown text that is just human-readable conversational threads related to the repository: bug reports, feature requests, questions or comments of any kind. Like patches, these SHOULD be sent to the relays specified in that repository's announcement event's `"relays"` tag.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is common place for titles to be updated by the author or maintainer to better reflect the issue at hand. What about an update mechanism similar to the status kind?

```jsonc
{
"kind": 1621,
"content": "<markdown text>",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about issue title? It could be a tag or the first line of the content with any markdown heading notation removed?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want Markdown here?

But yes, let's add a title tag.

"tags": [
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
["r", "<repository-unique-reference>"], // the earliest unique commit id. usually the root commit id unless it's a fork.

This associates the issue to the git repository. If the maintainer changes (or if there are multiple), clients can easily query relays for all issues.

["p", "<repository-owner>"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you could have a list of “p” - “other-user” in kind 1621 as generally you have many people working on large projects.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The p tag can be used on any event to bring it to a users attention. The explicit inclusion of this only in the Patch section of the nip is potentially confusing.

]
}
```

## Replies

Replies are also Markdown text. The difference is that they MUST be issued as replies to either a `kind:1621` _issue_ or a `kind:1617` _patch_ event. The threading of replies and patches should follow NIP-10 rules.

```jsonc
{
"kind": 1622,
"content": "<markdown text>",
"tags": [
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>", "<relay-url>"],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>", "<relay-url>"],
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>", "<relay-url>"],
["r", "<repository-unique-reference>"], // the earliest unique commit id. usually the root commit id unless it's a fork.

This associates the issue with the git repository. If the maintainer changes (or if there are multiple), clients can easily query relays for all issues.

["e", "<issue-or-patch-id-hex>", "", "root"],

// other "e" and "p" tags should be applied here when necessary, following the threading rules of NIP-10
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you could have “relay-local” threading policy on max default “p” elements.

["p", "<patch-author-pubkey-hex>", "", "mention"],
["e", "<previous-reply-id-hex>", "", "reply"],
// ...
]
}
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Pull Requests
{
"kind": 1623
"content": ""
"tags": [
["commit": "<sha1-commit-hash>"], //MUST
["web": "url where the repo can be viewed"], //OPTIONAL
["git": "url of standard git API"], //MUST
["p": "maintainer(s) pubkey"], //OPTIONAL
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"] //MUST
]
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each proposed commit / patch should have its own event so there is a record available for those who are interested in reviewing the of history how a change evolved over time before it got merged even if the contributor deletes the repo on their git server.

Patches that are too large for an event should have a special patch event type called a stub. This points to a git server for the full commit but contains most of the details of the patch but with only the large file diffs removed.
This way the salient details will be retained but large file diffs (often binary blobs) removed.

I agree their should be a PR event to hang multiple patches on - see #997 (comment).

## Possible things to be added later

- "status" kind (for letting people know a patch was merged or an issue was fixed or won't be fixed)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status is quite important. Shouldn't we add this now? Its impossible to identify open proposals or issues unless you are a maintainer with a client that stores the status internally.

- "branch merge" kind (specifying a URL from where to fetch the branch to be merged)
- "cover letter" kind (to which multiple patches can refer and serve as a unifying layer to them)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned in #997 (comment) we should have a cover_letter as a separate kind than a patch because it is different in nature.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between a "cover letter" kind and an "issue" kind?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cover letter is always paired with a proposed change. An issue may result in zero or more changes in the future.

- inline file comments kind (we probably need one for patches and a different one for merged files)