Lucas Vieira

Visualizing PR Dependencies

[Source] [Demo]

There was a time at work when we were drowning in PRs. Like, a lot of PRs. And when you’re trying to figure out which one to review first, or why merging one breaks another, or where the bottleneck in your deployment chain is… your brain starts to hurt.

So I built PRoot – a CLI that turns your GitHub PRs into an actual graph you can look at. Because sometimes you just need to see the mess you’re in.

The Problem

Here’s the thing: PRs don’t exist in isolation. PR #47 depends on #45, which depends on #42, which is blocked by #38 that nobody’s reviewed yet. And you’re sitting there wondering why nothing is moving forward.

GitHub shows you a list of PRs. It doesn’t show you how they connect. That’s where PRoot comes in.

What It Does

Run proot in any repo and you get a tree view of your PRs:

1┌ main
2├──○ [#47] feature/new-api - Add new API endpoints
3│  └──○ [#49] feature/api-tests - Add tests for new API
4├──○ [#45] fix/database - Fix database migration
5│  └──○ [#48] fix/db-tests - Add database tests
6└──○ [#42] refactor/cleanup - Code cleanup

Now you can actually see that #49 is blocked by #47, and #48 is blocked by #45. Review order: obvious.

You can also:

Why Rust?

I’ve been learning Rust, and this felt like the perfect project. It’s a CLI tool – no complex UI, just some data processing and pretty terminal output. Plus, I wanted to play with:

The whole thing is a wrapper around gh cli, parsing its JSON output and building a graph structure. Nothing fancy, but it works.

The Graph Part

The interesting bit is how I represent the PR relationships. Each PR has a head branch and a base branch. If PR A’s head is PR B’s base, then B depends on A.

I build an adjacency list where each base branch points to all the head branches that target it:

1pub struct PrGraph {
2    adjacency_list: HashMap<String, Vec<String>>,
3    prs: HashMap<String, Pr>,
4}

Then it’s just a DFS traversal to print the tree. The tricky part was handling cross-repository PRs (forks) and making sure the output actually looks like a tree with all those Unicode box-drawing characters.

Lessons Learned

Rust’s error handling is verbose but worth it. Every function returns a Result, and you handle errors explicitly. It’s more work upfront, but debugging is way easier because you’re forced to think about what can go wrong.

Graph algorithms are everywhere. I knew the theory from university, but actually implementing a DFS to traverse PR dependencies? That’s when it clicked.

Current Status

It’s published on crates.io, which is wild because I built it for myself and now other people apparently use it. The download count keeps going up and I have no idea who these people are.

If you’re drowning in PRs like we were, give it a try:

1cargo install proot

Or check out the repo if you want to see how it works.

#Rust #Cli