specs/GITREVIEW.md · main · 2026-06-28

GitReview Extension Specification

Code contribution and review extension for the GitMsg protocol (name: review, version: 0.1.0).

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

1. Messages

1.1. Types

For general comments on a pull request, see Section 1.6.

1.2. Pull Request Fields

Fields (in header order):

Field order: state, draft, base, base-tip, head, head-tip, depends-on, closes, merge-base, merge-head, reviewers, labels.

The head and base fields support full repository URLs, enabling cross-forge contributions (e.g., GitLab to GitHub).

1.3. Feedback Fields

Fields (in header order):

Field order: pull-request, commit, file, new-line, new-line-end, old-line, old-line-end, review-state, suggestion.

A feedback message MUST include at least one of: code-location fields (file, commit, and at least one of old-line or new-line) OR review-state.

Inline feedback (with code-location fields) MUST include file, commit, and at least one of old-line or new-line.

1.4. Message Rules

1.5. Editing and Retracting

Pull requests MAY be edited or retracted using core versioning (GITMSG.md Section 1.5). State transitions (open -> merged, open -> closed) are edits to the original pull-request commit. Draft transitions (adding or removing draft="true") are also edits. Implementations MUST NOT merge a pull request while draft="true". Implementations SHOULD suppress review request notifications for draft pull requests.

Implementations SHOULD include base-tip and head-tip when creating or editing a pull request. These fields capture the commit hashes (12 characters) that the base and head branches point to at the time of the commit. When a pull request's code is updated (e.g., after rebase or new commits), implementations SHOULD create an edit with updated base-tip and head-tip values. The edits chain serves as a version history of the pull request's code state, enabling implementations to compare any two versions via range-diff.

When transitioning to state="merged", implementations MUST include merge-base with the common ancestor commit hash (12 characters) and merge-head with the head branch tip commit hash (12 characters), both computed before the merge. These two fields are the only durable record of the merged commit range — head-tip and base-tip describe the live branches at edit time, but the head branch may be deleted afterward, leaving merge-base..merge-head as the sole reconstruction path for the diff. Implementations MUST refuse to record a state="merged" edit when either field cannot be computed (e.g., the head branch is missing or the merge-base is unreachable).

When resolving a cross-repository pull request (fork PR) by merge or close, implementations SHOULD first copy it to the upstream review branch, carrying adopts="<fork-pr-ref>" (naming the fork PR) and a GitMsg-Ref: trailer preserving the original author's identity. The resolving edit then references the local copy as canonical, ensuring the upstream has a self-contained record that survives fork deletion.

Feedback messages MAY be edited or retracted using core versioning. Implementations SHOULD display an edit indicator on modified messages.

1.6. Comments

Implementations MUST use GitSocial for pull request comments. The original field references the pull request commit:

Looks great, just one nit on the theme toggle.

GitMsg: ext="social"; type="comment"; original="#commit:abc123456789@gitmsg/review"; v="0.1.0"
GitMsg-Ref: ext="review"; type="pull-request"; author="Alice"; email="[email protected]"; time="2025-01-06T10:00:00Z"; ref="#commit:abc123456789@gitmsg/review"; v="0.1.0"
 > Add dark mode support

Nested comment threads use GitSocial's reply-to field.

1.7. Comment Anchoring

Inline reviews are anchored to specific file locations at a specific commit. When the PR branch is rebased or updated, implementations SHOULD attempt to map comment locations to the new commit:

  1. Match the file and surrounding context lines
  2. If no match, mark the comment as outdated

Anchoring is an implementation concern. Implementations MAY use different strategies for mapping comments across revisions.

1.8. Review Aggregation

Implementations SHOULD derive pull request review state from feedback commits that include review-state:

Implementations MAY enforce additional merge requirements via configuration.

2. Config

Configuration MUST be stored at refs/gitmsg/review/config:

{
  "version": "0.1.0",
  "branch": "gitmsg/review",
  "require-review": true
}

Configuration MUST include: version.

Configuration SHOULD include: branch. Default: gitmsg/review.

Configuration MAY include: require-review (boolean, default false).

Appendix: Manifest

{
  "name": "review",
  "version": "0.1.0",
  "display": "GitReview",
  "description": "Code contribution and review extension for GitMsg",
  "types": ["pull-request", "feedback"],
  "fields": ["base", "base-tip", "closes", "commit", "depends-on", "draft", "file", "head", "head-tip", "merge-base", "merge-head", "new-line", "new-line-end", "old-line", "old-line-end", "pull-request", "review-state", "reviewers", "state", "suggestion"]
}

Appendix: Validation

FieldPattern
state (pull-request)`open\merged\closed`
drafttrue
review-state`approved\changes-requested`
filerelative path, no leading slash
old-linepositive integer, 1-indexed
old-line-endpositive integer, 1-indexed
new-linepositive integer, 1-indexed
new-line-endpositive integer, 1-indexed
commit12-character hash
reviewerscomma-delimited email addresses
depends-oncomma-separated pull request references
closescomma-separated issue references
base-tip12-character hash
head-tip12-character hash
merge-base12-character hash; required when state="merged", prohibited otherwise
merge-head12-character hash; required when state="merged", prohibited otherwise
suggestiontrue

Appendix: Examples

Create Pull Request

Add dark mode support

GitMsg: ext="review"; type="pull-request"; state="open"; base="#branch:main"; base-tip="f1e2d3c4b5a6"; head="#branch:dark-mode"; head-tip="a1b2c3d4e5f6"; closes="#commit:abc123456789@gitmsg/pm"; reviewers="[email protected]"; v="0.1.0"

Create Draft Pull Request

WIP: Add dark mode support

GitMsg: ext="review"; type="pull-request"; state="open"; draft="true"; base="#branch:main"; head="#branch:dark-mode"; head-tip="a1b2c3d4e5f6"; v="0.1.0"

Mark Draft as Ready

Add dark mode support

GitMsg: ext="review"; type="pull-request"; edits="#commit:abc123456789@gitmsg/review"; state="open"; base="#branch:main"; base-tip="f1e2d3c4b5a6"; head="#branch:dark-mode"; head-tip="a1b2c3d4e5f6"; reviewers="[email protected]"; v="0.1.0"

Approve Pull Request

LGTM!

GitMsg: ext="review"; type="feedback"; pull-request="#commit:abc123456789@gitmsg/review"; review-state="approved"; v="0.1.0"
GitMsg-Ref: ext="review"; type="pull-request"; author="Alice"; email="[email protected]"; time="2025-01-20T10:00:00Z"; ref="#commit:abc123456789@gitmsg/review"; v="0.1.0"
 > Add dark mode support

Inline Review Comment

Consider caching this value

GitMsg: ext="review"; type="feedback"; pull-request="#commit:abc123456789@gitmsg/review"; commit="def456789abc"; file="src/theme.js"; new-line="42"; v="0.1.0"
GitMsg-Ref: ext="review"; type="pull-request"; author="Alice"; email="[email protected]"; time="2025-01-20T10:00:00Z"; ref="#commit:abc123456789@gitmsg/review"; v="0.1.0"
 > Add dark mode support

Suggestion

~~~ Use a CSS custom property for the transition

transition: background-color var(--theme-transition, 200ms) ease;

GitMsg: ext="review"; type="feedback"; pull-request="#commit:abc123456789@gitmsg/review"; commit="def456789abc"; file="src/theme.css"; new-line="18"; suggestion="true"; v="0.1.0" GitMsg-Ref: ext="review"; type="pull-request"; author="Alice"; email="[email protected]"; time="2025-01-20T10:00:00Z"; ref="#commit:abc123456789@gitmsg/review"; v="0.1.0"

Add dark mode support

~~~

Merge Pull Request

Add dark mode support

GitMsg: ext="review"; type="pull-request"; edits="#commit:abc123456789@gitmsg/review"; state="merged"; base="#branch:main"; base-tip="f1e2d3c4b5a6"; head="#branch:dark-mode"; head-tip="d4e5f6a1b2c3"; closes="#commit:abc123456789@gitmsg/pm"; merge-base="f1e2d3c4b5a6"; merge-head="d4e5f6a1b2c3"; reviewers="[email protected]"; v="0.1.0"

Retract Pull Request

GitMsg: ext="review"; edits="#commit:abc123456789@gitmsg/review"; retracted="true"; v="0.1.0"

Cross-Forge Pull Request

Add dark mode support

GitMsg: ext="review"; type="pull-request"; state="open"; base="https://github.com/bob/repo#branch:main"; base-tip="f1e2d3c4b5a6"; head="https://gitlab.com/alice/repo#branch:dark-mode"; head-tip="a1b2c3d4e5f6"; v="0.1.0"

Merge Cross-Repo Pull Request

Step 1 - Copy fork PR to upstream (preserves original author via GitMsg-Ref):

Add dark mode support

GitMsg: ext="review"; type="pull-request"; state="open"; base="#branch:main"; base-tip="f1e2d3c4b5a6"; head="https://gitlab.com/alice/repo#branch:dark-mode"; head-tip="a1b2c3d4e5f6"; v="0.1.0"
GitMsg-Ref: ext="review"; type="pull-request"; author="Alice"; email="[email protected]"; time="2025-01-20T10:00:00Z"; ref="https://gitlab.com/alice/repo#commit:abc123456789@gitmsg/review"; v="0.1.0"
 > Add dark mode support

Step 2 - Merge edit references the local copy:

Add dark mode support

GitMsg: ext="review"; type="pull-request"; edits="#commit:def456789abc@gitmsg/review"; state="merged"; base="#branch:main"; base-tip="f1e2d3c4b5a6"; head="https://gitlab.com/alice/repo#branch:dark-mode"; head-tip="a1b2c3d4e5f6"; merge-base="f1e2d3c4b5a6"; merge-head="a1b2c3d4e5f6"; v="0.1.0"