From 3be0d2e2ac7ba0f206b0dc2be971ea62781db59e Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 16 Apr 2025 16:30:13 +0100 Subject: [PATCH] reword entire thing be more to the point: - use shorter sentences - flow properly from web ui to review --- pages/blog/pulls.md | 237 +++++++++++++++++++++----------------------- 1 file changed, 115 insertions(+), 122 deletions(-) diff --git a/pages/blog/pulls.md b/pages/blog/pulls.md index 4a2ea42..84e2490 100644 --- a/pages/blog/pulls.md +++ b/pages/blog/pulls.md @@ -15,169 +15,162 @@ authors: draft: true --- -We've spent the last few weeks building out a pull request system for Tangled, -and today we want to lift the hood and show you how it works. What makes our -implementation particularly interesting is that Tangled is federated -- -repositories can exist across different servers (which we call "knots"). This -distributed nature creates unique engineering challenges that we had to solve. +We've spent the last couple of weeks building out a pull +request system for Tangled, and today we want to lift the +hood and show you how it works. -If you're new to Tangled and wondering what this knot business is all about, -[read our intro](/intro) for the full story! +If you're new to Tangled, [read our intro](/intro) for the +full story! -Now, on with the show! +You have three options to contribute to a repository: -## your patch makes the rounds - -Creating a PR in Tangled starts with heading to `/pulls/new` in your -target repository. Once there, you're presented with three options: - -- Paste a patch +- Paste a patch on the web UI - Compare two local branches (you'll see this only if you're a collaborator on the repo) - Compare across forks -Whatever you choose, at the core of every PR is the patch. You either -supply it and make everyone's lives easier, or we generate it ourselves -by comparing branches (we'll talk more about this in a bit, it's very -cool actually). We'll skip explaining the part where you click around on -the UI to create a new PR -- instead, let's talk about what comes after. +Whatever you choose, at the core of every PR is the patch. +First, you write some code. Then, you run `git diff` to +produce a patch and make everyone's lives easier, or push to +a branch, and we generate it ourselves by comparing against +the target. -We call it "rounds". Each round consists of a code review: your patch recieves -scrutiny, and updating the patch in response, results in a new round. Rounds are -obviously 0-indexed. Here's an example. +## patch generation -
- -
A new pull request with a couple -rounds of reviews. Thanks Jay!
+When you create a PR from a branch, we create a "patch" by +calculating the difference between your branch and the +target branch. Consider this scenario: + +
+ +
Merge base caption here! [!!!change this!]
-Rounds are a far superior to standard branch-based -approaches: +Your `feature` branch has advanced 2 commits since you first +branched out, but in the meanwhile, `main` has also advanced +2 commits. Doing a trivial `git diff feature main` will +produce a confusing patch: -- Submissions are immutable: how many times have your - reviews gone out-of-date because the author pushed commits - _during_ your review? -- Reviews are attached to submissions: at a glance, it is - easy to tell which comment applies to which "version" of the - pull-request -- The author can choose when to resubmit! They can commit as - much as they want, but a new round begins when they choose - to hit "resubmit" -- It is possible to "interdiff" and observe changes made - across submissions (this is coming very soon to Tangled!) +- the patch will apply the changes from X and Y +- the patch will **revert** the changes from B and C -This [post by Mitchell -Hashimoto](https://mitchellh.com/writing/github-changesets) goes into further -detail on what can be achieved with round-based reviews. +We obviously do not want the second part! To only show the +changes added by `feature`, we have to identify the +"merge-base": the nearest common ancestor of `feature` and +`main`. -## fine, we'll make a patch ourselves -Remember our patch from earlier? Yeah, let's get into how comparing branches works. +In this case, `A` is the nearest common ancestor, and +subsequently, the patch calculated will contain just `X` and +`Y`. -[you gotta talk about] -- merge and merge check? -- merge base thing -- sh.tangled.repo.patch lexicon -- nice segue into the fork section +### ref comparisons across forks +The plumbing described above is easy to do across two +branches, but what about forks? and what if they live on +different servers altogether (as they can in tangled!)? -
- -
Merge base caption here! [!!!change this!]
-
+Here's the concept: since we already have all the necessary +components to compare two local refs, why not simply +"localize" the remote ref? +In simpler terms, we instruct Git to fetch the target branch +from the original repository and store it in your fork under +a special name. This approach allows us to compare your +changes against the most current version of the branch +you're trying to contribute to, all while remaining within +your fork. -[!!!do we want this? use it to explain the patch merge/check process maybe]
- -
Simplified pull request flow.
+ +
Hidden tracking ref.
+We call this a "hidden tracking ref." When you create a pull +request from a fork, we establish a refspec that tracks the +remote branch, which we then use to generate a diff. A +refspec is essentially a rule that tells Git how to map +references between a remote and your local repository during +fetch or push operations. -## quick detour: what's in a fork? - -Forks are just "clones" of another repository. They aren't your typical -clones from `git clone` however, since we're operating on top of [bare -repositories][bare-repo]. Hence, forks are "bare clones". You can create -one yourself locally: +For example, if your fork has a feature branch called +`feature-1`, and you want to make a pull request to the +`main` branch of the original repository, we fetch the +remote `main` into a local hidden ref using a refspec like +this: ``` -git clone --bare git@tangled.sh:tangled.sh/core ++refs/heads/main:refs/hidden/feature-1/main ``` -[bare-repo]: https://git-scm.com/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server - -On Tangled, forking a repo results in a new -[`sh.tangled.repo`][repo-record] record in your PDS. What's interesting -is the new `source` field that's an AT URI pointing to the original -repository: +Since we already have a remote (`origin`, by default) to the +original repository (remember, we cloned it earlier), we can +use `fetch` with this refspec to bring the remote `main` +branch into our local hidden ref. Each pull request gets its +own hidden ref, hence the `refs/hidden/:localRef/:remoteRef` +format. We keep this ref updated whenever you push new +commits to your feature branch, ensuring that comparisons -- +and any potential merge conflicts -- are always based on the +latest state of the target branch. - { - "knot": "test.hel.tangled.network", - "name": "core", - "$type": "sh.tangled.repo", - "owner": "did:plc:hwevmowznbiukdf6uk5dwrrq", - "source": "at://did:plc:wshs7t2adsemcrrd4snkeqli/sh.tangled.repo/3liuighjy2h22", - "addedAt": "2025-04-14T12:53:45Z" - } +And just like earlier, we produce the patch by diffing your +feature branch with the hidden tracking ref and do the whole +atproto record thing. -[repo-record]: https://pdsls.dev/at://did:plc:hwevmowznbiukdf6uk5dwrrq/sh.tangled.repo/3lmrm7gu5dh22 +Neat, now that we have a patch; we can move on the hard +part: code review. -Great, we've got a fork on your knot now. You can now work on your change safely -here -- but let's get back to how we generate a patch across forks. -### ref comparisons across forks +## your patch does the rounds -We'll admit: we ... skipped some sneaky bits about forks earlier. Here's the -concept: since we already have all the necessary components to compare two local -refs, why not simply "localize" the remote ref? +Tangled uses a "round-based" review format. Your initial +submission starts "round 0". Once your submission receives +scrutiny, you can address reviews and resubmit your patch. +This resubmission starts "round 1". You keep whittling on +your patch till it is good enough, and eventually merged (or +closed if you are unlucky). -In simpler terms, we instruct Git to fetch the target branch from the original -repository and store it in your fork under a special name. This approach allows -us to compare your changes against the most current version of the branch you're -trying to contribute to, all while remaining within your fork. - -
- -
Hidden tracking ref.
+
+ +
A new pull request with a couple +rounds of reviews. Thanks Jay!
-We call this a "hidden tracking ref." When you create a pull request from a -fork, we establish a refspec that tracks the remote branch, which we then use to -generate a diff. A refspec is essentially a rule that tells Git how to map -references between a remote and your local repository during fetch or push -operations. - -For example, if your fork has a feature branch called `feature-1`, and you want -to make a pull request to the `main` branch of the original repository, we fetch -the remote `main` into a local hidden ref using a refspec like this: - -``` -+refs/heads/main:refs/hidden/feature-1/main -``` +Rounds are a far superior to standard branch-based +approaches: -Since we already have a remote (`origin`, by default) to the original repository -(remember, we cloned it earlier), we can use `fetch` with this refspec to bring -the remote `main` branch into our local hidden ref. Each pull request gets its -own hidden ref, hence the `refs/hidden/:localRef/:remoteRef` format. We keep -this ref updated whenever you push new commits to your feature branch, ensuring -that comparisons -- and any potential merge conflicts -- are always based on the -latest state of the target branch. +- Submissions are immutable: how many times have your + reviews gone out-of-date because the author pushed commits + _during_ your review? +- Reviews are attached to submissions: at a glance, it is + easy to tell which comment applies to which "version" of + the pull-request +- The author can choose when to resubmit! They can commit as + much as they want to their branch, but a new round begins + when they choose to hit "resubmit" +- It is possible to "interdiff" and observe changes made + across submissions (this is coming very soon to Tangled!) -And just like earlier, we produce the patch by diffing your feature branch with -the hidden tracking ref and do the whole atproto record thing. +This [post by Mitchell +Hashimoto](https://mitchellh.com/writing/github-changesets) +goes into further detail on what can be achieved with +round-based reviews. ## future plans -To close off this post, we wanted to share some of our future plans for pull requests: +To close off this post, we wanted to share some of our +future plans for pull requests: -* `format-patch` support: both for pasting in the UI and internally. This allows -us to show commits in the PR page, and offer different merge strategies to -choose from (squash, rebase, ...). +* `format-patch` support: both for pasting in the UI and + internally. This allows us to show commits in the PR page, + and offer different merge strategies to choose from + (squash, rebase, ...). -* Gerrit-style `refs/for/main`: we're still hashing out the details but being -able to push commits to a ref to "auto-create" a PR would be super handy! +* Gerrit-style `refs/for/main`: we're still hashing out the + details but being able to push commits to a ref to + "auto-create" a PR would be super handy! -* Change ID support: This will allow us to group changes together and track them -across multiple commits, and to provide "history" for each change. +* Change ID support: This will allow us to group changes + together and track them across multiple commits, and to + provide "history" for each change. This works great with + `jujutsu`. -- 2.51.2