惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
Cyberwarzone
Cyberwarzone
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
小众软件
小众软件
Recent Announcements
Recent Announcements
博客园 - 三生石上(FineUI控件)
Security Archives - TechRepublic
Security Archives - TechRepublic
W
WeLiveSecurity
Cloudbric
Cloudbric
博客园 - 司徒正美
美团技术团队
N
News and Events Feed by Topic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
PCI Perspectives
PCI Perspectives
宝玉的分享
宝玉的分享
H
Help Net Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
Help Net Security
Help Net Security
Last Week in AI
Last Week in AI
S
Schneier on Security
N
News | PayPal Newsroom
B
Blog RSS Feed
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
S
Secure Thoughts
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
L
Lohrmann on Cybersecurity
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tenable Blog
S
Securelist
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
I
InfoQ
H
Heimdal Security Blog
Cisco Talos Blog
Cisco Talos Blog
F
Full Disclosure
Y
Y Combinator Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
K
Kaspersky official blog
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
阮一峰的网络日志
阮一峰的网络日志
C
Cisco Blogs

Graphite blog

Introducing Code Tours: a new way to review Introducing Cursor Cloud Agents in Graphite Building the future of software development with Cursor Reimagining the PR Page: Designing for speed and focus Graphite changelog [11-20-2025] Graphite changelog [11-04-2025] Graphite changelog [10-16-2025] The future of engineering is collaborative (and already here) Meet Graphite Agent: the next evolution of AI code review Introducing frozen branches: A safer way to build on your teammates’ work Graphite changelog [09-17-2025] Introducing Graphite Chat AI is writing code—here's why it also needs to review that code How I got Claude to write code I could actually ship How we built the first stack-aware merge queue (and why it matters) How we organize our monorepo to ship fast Graphite brings stacking to Tower Code review tooling: Should you build or buy? Making AI code review available to everyone Introducing: The new Graphite + Linear integration Graphite raises $52M and launches Diamond to reimagine code review for the age of AI Why AI will never replace human code review How stacked PRs unblock distributed development teams Graphite is going to Developer Week 2025 Beating the end of year code freeze How Graphite’s eng team ships code remarkably fast Why we chose Anthropic's Claude to power Graphite Reviewer AI code generation will remain fragmented How we redesigned Graphite's landing page in-house Introducing Graphite Reviewer: your AI code review companion How AI code review reduces review cycles to improve developer productivity What if you could get instant feedback on your code? The new developer toolchain Not Rocket Science - How Bors and Google’s TAP inspired modern merge queues Graphite's State of code review 2024 How Google migrated billions of lines of code from Perforce to Piper Going from 0 to 1: How to write better unit tests when there are none Speed up your merges: Parallel CI is now generally available for teams using Graphite’s merge queue Down for less than four minutes a month: how AWS deploys code BitKeeper, Linux, and licensing disputes: How Linus wrote Git in 14 days Graphite is now free for startups and open source projects Launch week wrap-up (May 2024) Reduce CI costs for Buildkite and GitHub Actions Cheaper CI & faster merging with batching How Google does code review The technical learning curve at a startup is gentler than you might think Graphite will now automatically rebase your partially-merged stacks Multiple engineers can now seamlessly collaborate on the same stack of PRs Do you ever outgrow GitHub? From the 80's to 2024 - how CI tests were invented and optimized Graphite changelog [4/10/2024] 🎺 Graphite changelog [4/25/2024] 🐸 How Stack Overflow replaced Experts Exchange How GitHub monopolized code hosting Graphite changelog [3/27/2024] 🤝 The core principles of building a good AI feature Onboarding roulette: deleting our employee accounts daily Graphite changelog [3/13/2024] 🚁 Why Facebook doesn’t use Git How to recreate the Phabricator code review workflow Types of code reviews: Improve performance, velocity, and quality What's the best GitHub pull request merge strategy? Phabricator vs GitHub vs Graphite: How do they stack up? Improving team velocity through better pull request practices Moving fast breaks things: the importance of a staging environment Building trust as a software engineer Keeping code simple: moving fast by avoiding over-engineering What's better than GitHub pull request filters? The Graphite pull request inbox 7 Best Phabricator alternatives for PR stacking + code review [2024] Accurate eng estimations: predicting and negotiating the future Tracking and understanding GitHub PR stats: A step-by-step guide 8 pull request best practices for optimal engineering What’s next for Graphite Graphite Q1 Launch week: Stacking with the tools you love Graphite Q1 Launch week: Making stacking seamless Accelerating code review The Mom Test How to use stacked PRs to unblock your entire team Graphite Q1 launch week 2024 The practical and philosophical problems with AI code review Empirically sup code review best practices Call site attribution: how to pinpoint rogue SQL queries throttling your performance Every engineer should understand git reflog Post mortem: we took 124 seconds from you, here's 378 back Your GitHub pull request workflow is slowing everyone down Optimizing CI/CD workflows for trunk-based development Why we use AWS instead of Vercel to host our Next.js app How large pull requests slow down development 3 key lessons in application server optimization Trunk-based development: why you should stop using feature branches Git was built in 5 days Why large companies and fast-moving startups are banning merge commits How long should your CI take? Experimenting with AI code review CRA to AppRouter in 5 Steps: A case study with Graphite Graphite Changelog [10/18/2023] The comprehensive guide to writing the best PR title of all time How 10,000 Developers All Contribute to the same Repo
How we sped up code search for Graphite Chat
Brandon Will · 2025-09-10 · via Graphite blog

Searching a codebase is usually a pretty easy problem. You want to know what files use your MAX_EMAILS_TO_SEND constant? One command gets you there in milliseconds:

grep -r MAX_EMAILS_TO_SEND .

Modern tools like ripgrep make it even faster. But this simplicity depends on a couple of things being true:

  • Your files all reside on a (hopefully) fast disk.

  • There aren't too many of them.

When building out a code search tool for the agentic Graphite Chat, we immediately ran into both of these limitations. We needed to support searches across hundreds of thousands (or millions) of files, at any commit, without maintaining a whole traditional VM+disk for each one. Could grep even support that kind of use case?

Let’s find out!

Default-branch-only search isn’t enough

You might read this and think: What's supposed to be novel here? We've had fast code search via API for big repositories for years now. Sourcegraph made a whole company out of the idea, and GitHub even gives you something similar for free.

True, but only on the default branch. GitHub’s API docs are explicit:

Only the default branch is considered. In most cases, this will be the main branch.

And Sourcegraph, while it’s closed-source now, still has an archive of their documentation and code as it stood in 2023, which details the same thing:

Sourcegraph also has a fast search path for code that isn't indexed yet, or for code that will never be indexed (for example: code that is not on a default branch). Indexing every branch of every repository isn't a pragmatic use of resources for most customers, so this decision balances optimizing the common case (searching all default branches) with space savings (not indexing everything).

Provides on-demand unindexed search for repositories. It scans through a git archive fetched from gitserver to find results, similar in nature to git grep.

The searches our model makes almost never target main; they’re against arbitrary commits. For us, fast search at any commit was the requirement, and that turned out to be a much harder problem.

What didn’t work

In the spirit of KISS (or “Choose Boring Technology”, or “The Grug Brained Developer”, feel free to pick your favorite decade’s spin on the idea), we figured our first attempt at a solution should also be the most straightforward: a plain old git grep on the repository. If that worked, then we could save ourselves a lot of time.

We spent a week running experiments on several block-based storage solutions on AWS:

  • On-demand AWS Lambdas to execute searches via one shared EFS volume.

  • An ECS cluster where tasks dynamically mount per-repo EFS volumes at query time.

  • Persistent EC2 instances which use (faster) EBS with multi-attach for horizontal scaling.

We saw some interesting results here, for example, we measured the EBS-mounted volumes to consistently perform I/O intensive operations (like searches) about 3x as fast as EFS-mounted ones. From a test we ran searching for a string in the react-native repository:

Performance counter stats for 'git grep interactionManager 8f1ae53':

17,541 minor-faults

878 major-faults

282.34 msec task-clock

1.535785602 seconds time elapsed

0.208365000 seconds user

0.075011000 seconds sys

Performance counter stats for 'git grep interactionManager 8f1ae53':

17,620 minor-faults

53 major-faults

354.59 msec task-clock

4.560184652 seconds time elapsed

0.212312000 seconds user

0.129052000 seconds sys

However, in spite of the individual advantages each had over the others, they all buckled in the same place: large repositories.

While react-native is a decently-sized repo by most measures, it only has a few thousand files:

$ git ls-files | wc -l

7019

We need to support repositories hundreds of times this size, and in cases like that, we actually end up at the mercy of the Linux page cache. The major-faults rows in the snippets above represent times the grep process needed to actually reach out to the disk for blocks, and for sample large codebases we tested, searches only returned “fast enough” (under 10 seconds) when major-faults was 0 (for instance, when the same search is run twice in a row). In other words, searches are fast only when the entire repository is already in the page cache.

At this point, the grep operation becomes mostly CPU bound, and perhaps unsurprisingly, this is also where EFS and EBS see their performance disparity vanish:

Performance counter stats for 'git grep interactionManager 8f1ae53':

17,667 minor-faults

0 major-faults

248.55 msec task-clock

0.259805935 seconds time elapsed

0.208592000 seconds user

0.040113000 seconds sys

Of course, the only way of ensuring that every block needed for a search is already in the page cache when the search comes in, is to have a crystal ball, which we can’t afford.

So, we have to look into some more earthly solutions!

What somewhat worked

If we can't brute-force our way through a big repository with grep, then it looks like we'll need to do some indexing.

We tested loading the repository’s files into Elasticsearch, which tokenizes documents and executes keyword queries quickly. The results were promising:

$ cat search.json

{

"query": {

"wildcard": {

"content": {

"value": "*interactionManager*"

}

}

}

}

$ https GET <elastic-endpoint>/blobs/_search?size=100 < search.json

{

"hits": {

"hits": [...],

"max_score": 1.0,

"total": {

"relation": "eq",

"value": 83

}

},

"timed_out": false,

"took": 79

}

Even using a tiny node type (i4g.large.search), we saw searches over even huge repositories taking well under 500ms. And that's with a cluster of just one node; we could easily split the dataset into shards (ES manages this on its own) such that 10 different nodes handle 1/10 of the files each, and our searches would be even faster.

Problem solved, right? Not quite. What we just tried with Elasticsearch worked great for one commit, but our requirement was fast search at any commit. The direct approach would be to index the repo’s state at each commit, for easy lookups, but — multiply thousands of repos by thousands of files by thousands of commits, and suddenly you’re managing tens of billions of documents. Running a cluster of that size would be prohibitively complex and expensive.

So, is the “document database” idea dead-on-arrival?

Back to basics

When looking at the problem through the above lens (the challenge of efficiently managing thousands of files, each with potentially thousands of versions), there is one database that's relevant to the discussion: namely, Git itself!

A Git repository seems to store an entire copy of the repository at each commit of a potentially-decades-long history, but does so without terabytes of disk space. This led us to wonder, "how does it do that, and can we somehow adapt that approach to work with a document search database instead of a filesystem?"

For the "how" question, it's honestly very clever if you haven't read about it before. The short version is, Git splits the data it stores into several different kinds of objects:

  1. Blobs → raw file contents, content-addressed.

  2. Trees → lists of blob IDs at a given commit.

And as for the "can we" question, it turns out, yes absolutely!

The life of a search query

The key change was that, like Git, we needed to start storing two kinds of objects instead of just one: the blobs and trees. Then, when it comes time to perform a search, we execute 2 queries:

  1. Get the tree object for the commit SHA specified in the query.

  2. Get all blobs that match the search term specified in the query.

And then, in memory, we filter the results from (2) based on the blob IDs in the result of (1), such that we only return files which are actually in-scope for the request. Easy!

Both of these queries are fast. The first simply retrieves a single document by its ID. While the second does need to consider every version of every file in the repo (which might sound like a lot), our tests show it’s actually not nearly so bad. Some files in the repository have dozens of unique versions, but the vast majority are rarely—if ever—updated. So the total number of documents is generally a small multiple (think ~3x) of the number of files you see in the working tree.

Plus, we’ve made a few optimizations to help things move even faster. If you notice, the above 2 queries are totally independent—you don’t need the result from (1) in order to perform (2), so we do them in parallel. And because a commit’s tree (which just specifies a set of blob IDs) is often much smaller than the result set of blobs, we’ve implemented the in-memory filter as a stream transformer, so that we can start responding to the client the moment we receive our first in-scope match.

The future

We have a few other ideas for optimizations, some a bit more experimental. For example, if we only ever use the tree for a set-contains operation, do we even need to fetch the entire tree at all? Maybe we can pre-construct the set of blob IDs, and only fetch that at query time, or even pre-construct something that acts just like that set, most of the time, but is just 10% the size?

And since we’re using Turbopuffer as the document database backing the Graphite code index, adding embeddings is on the table too, which opens the door to semantic search. Maybe we will soon be able to ask PR Chat to check if a pattern you tried is consistent with examples from similar files.

The now

Today, the system is live, and we’ve already indexed tens of millions of source files across thousands of repositories. For several weeks, Graphite Chat has been using this index to power LLM tool calls, where it’s been a big upgrade from our previous strategy of calling the GitHub API.

We can now fetch as many files as we need (no arbitrary rate limit), our searches accurately target the PR’s branch (instead of only being able to search main), and best of all — the index has now served thousands of queries with a median latency consistently under 100 milliseconds.

What started as a “just grep it” idea turned into a deep dive through storage tradeoffs, indexing engines, and Git’s internals. By rethinking search in terms of blobs and trees, we’ve unlocked fast search at any commit—something we couldn’t get off the shelf. And we’ve hardly touched on the ingestion part! It turns out there are ways to have Git shrink a 5GB repo clone down to 20MB, and you'd be surprised how useful an anemic clone like that can still be.

Which is to say, check back soon for a part two!