Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
166 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge branch 'worktree-agent-a6a121745e81f639f'1//! What g1t adds around a pull request for many agents working at once:
2//! which files it changes, which other pull requests are changing the same
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.3//! files, and whether it has fallen behind.
Merge branch 'worktree-agent-a6a121745e81f639f'4
5use std::collections::HashSet;
6
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.7use g1t_contracts::repos::{BehindArgs, Comparison, GetByIdArgs, Repo, RepoPath};
Merge branch 'worktree-agent-a6a121745e81f639f'8use g1t_contracts::work::*;
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.9use g1t_contracts::{FailureCode, Outcome};
Merge branch 'worktree-agent-a6a121745e81f639f'10use serde::Deserialize;
11use worker::Result;
12
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.13use crate::Work;
Merge branch 'worktree-agent-a6a121745e81f639f'14use crate::rows::{PULL_COLUMNS, PullRow};
15
16/// Beyond this a change is too large for per-file bookkeeping to be useful.
17const MAX_FILES: usize = 300;
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.18/// g1t's agent, which wrote reviews and pull requests before g1t stopped
19/// hosting agents: shown as `g1t`, which nobody can register or sign in as.
Merge branch 'worktree-agent-a6a121745e81f639f'20pub(crate) use g1t_contracts::identity::{AGENT_ID, AGENT_NAME};
21
22#[derive(Deserialize)]
23struct OtherRow {
24 number: u32,
25 title: String,
26 issue_number: Option<u32>,
27 files: Option<String>,
28}
29
30impl Work {
31 pub(crate) async fn pull_by_id(&self, id: &str) -> Result<Option<Pull>> {
32 Ok(self
33 .db
34 .prepare(format!("SELECT {PULL_COLUMNS} FROM pulls WHERE id = ?"))
35 .bind(&[id.into()])?
36 .first::<PullRow>(None)
37 .await?
38 .map(Pull::from))
39 }
40
41 /// Works out which files a pull request changes and records them, so
42 /// that overlaps between pull requests can be found without comparing
43 /// every one of them each time.
44 pub(crate) async fn refresh_files(&self, pull: &Pull) -> Result<Vec<ChangedFile>> {
45 // Its owner (whoever asked g1t for it, or its author) can read both
46 // the repository and the pull request's source.
47 let viewer = self.owner_viewer(pull).await?;
48 let compared: Outcome<Comparison> =
49 g1t_kit::call(&self.repos, "compare", &pull.comparison(&viewer)).await?;
50 let files: Vec<ChangedFile> = match compared {
51 Outcome::Ok(comparison) => comparison
52 .files
53 .into_iter()
54 .take(MAX_FILES)
55 .map(|file| ChangedFile {
56 path: file.path,
57 additions: file.additions,
58 deletions: file.deletions,
59 })
60 .collect(),
61 // Nothing pushed yet, or nothing to compare against.
62 Outcome::Fail(_) => Vec::new(),
63 };
64 self.db
65 .prepare("UPDATE pulls SET files = ? WHERE id = ?")
66 .bind(&[
67 serde_json::to_string(&files)?.into(),
68 pull.id.as_str().into(),
69 ])?
70 .run()
71 .await?;
72 Ok(files)
73 }
74
75 /// Other pull requests in progress that change files this one changes.
76 pub(crate) async fn overlaps(&self, pull: &Pull) -> Result<Vec<Overlap>> {
77 if pull.files.is_empty() {
78 return Ok(Vec::new());
79 }
80 let mine: HashSet<&str> = pull.files.iter().map(|file| file.path.as_str()).collect();
81 let others = match self.prefetched_pull(&pull.id) {
82 Some(found) => found.rows::<OtherRow>(crate::prefetch::Slot::Others)?,
83 None => self.other_pulls(pull).await?,
84 };
85 Ok(others
86 .into_iter()
87 .filter_map(|other| {
88 let files: Vec<ChangedFile> =
89 serde_json::from_str(other.files.as_deref().unwrap_or("[]")).ok()?;
90 let paths: Vec<String> = files
91 .into_iter()
92 .map(|file| file.path)
93 .filter(|path| mine.contains(path.as_str()))
94 .collect();
95 (!paths.is_empty()).then_some(Overlap {
96 number: other.number,
97 title: other.title,
98 issue: other.issue_number,
99 paths,
100 })
101 })
102 .collect())
103 }
104
105 /// The other pull requests in progress in its repository.
106 async fn other_pulls(&self, pull: &Pull) -> Result<Vec<OtherRow>> {
107 self
108 .db
109 .prepare(
110 "SELECT number, title, issue_number, files FROM pulls
111 WHERE repo_id = ? AND id != ? AND status IN ('draft', 'open')
112 ORDER BY number LIMIT 200",
113 )
114 .bind(&[pull.repo_id.as_str().into(), pull.id.as_str().into()])?
115 .all()
116 .await?
117 .results::<OtherRow>()
118 }
119
120 /// Whether the branch a pull request would merge into has commits the
121 /// pull request does not, so that it must catch up before it can merge.
122 pub(crate) async fn is_behind(&self, repo_id: &str, pull: &Pull) -> Result<bool> {
123 if !pull.status.is_active() || pull.head_commit.is_none() {
124 return Ok(false);
125 }
126 let asked = BehindArgs {
127 source_id: pull
128 .fork_repo_id
129 .clone()
130 .unwrap_or_else(|| repo_id.to_owned()),
131 branch: pull.branch.clone(),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar132 target_branch: pull.base.clone().filter(|base| !base.is_empty()),
Merge branch 'worktree-agent-a6a121745e81f639f'133 };
134 self.timing.rpc(g1t_kit::call(&self.repos, "behind", &asked)).await
135 }
136
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.137 /// Where a pull request lives, for a tool that knows only its id (its
138 /// fork is named after it).
139 pub(crate) async fn locate_pull(&self, a: LocatePullArgs) -> Result<Outcome<LocatedPull>> {
140 let missing = || Outcome::fail(FailureCode::NotFound, "Pull request not found.");
141 let Some(pull) = self.pull_by_id(&a.id).await? else {
142 return Ok(missing());
Merge branch 'worktree-agent-a6a121745e81f639f'143 };
144 let repo: Outcome<Repo> = g1t_kit::call(
145 &self.repos,
146 "get_by_id",
147 &GetByIdArgs {
148 id: pull.repo_id.clone(),
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.149 viewer: a.viewer,
Merge branch 'worktree-agent-a6a121745e81f639f'150 },
151 )
152 .await?;
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.153 let Outcome::Ok(repo) = repo else {
154 return Ok(missing());
Merge branch 'worktree-agent-a6a121745e81f639f'155 };
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.156 Ok(Outcome::Ok(LocatedPull {
157 repo: RepoPath {
158 namespace: repo.namespace,
159 name: repo.name,
Merge branch 'worktree-agent-a6a121745e81f639f'160 },
161 number: pull.number,
162 title: pull.title,
The work, events, webhooks, actions, repos and packages services no longer run g1t's own agents. Work drops the 35 calls that queued issues for g1t, delegated them, messaged and reviewed through the agent, planned, captured memories automatically, rated confidence and capped agent spend, and its pull request lifecycle no longer revises or reviews: a pull request only advances to a merge by the repository's auto-merge setting. Merging a pull request that is behind now catches it up itself, through the repository's branch update, and lands it when the push arrives; when it can't be caught up cleanly the merge says to merge the base in and try again. Recording a session on a pull request, memory recall and remember, overlaps, the merge queue and required checks stay as they were.163 status: pull.status,
Merge branch 'worktree-agent-a6a121745e81f639f'164 }))
165 }
166}

This file's history is long; its oldest lines are credited to the oldest commit read.