HNHacker News
TopNewBestAskShowJobs

schacon

2,773 karma · joined March 12, 2008

works at GitButler. loves kittens, ruby and git.
submissionscomments
schacon··on Looking forward to Git 2.56 – and 3.0
JJ and GitButler already create and inject this into the commit headers (using the same interoperable reverse-hex format), which is recognized by Gerrit and some forges like Tangled for incremental commit based review.

I doubt that core Git will adopt it anytime soon as it was not discussed at this years contributor summit (last week) and doesn't seem to be a hot topic on the ML.

What I would like to see is support for `git rebase` not dropping it, which is the current main issue. The `git replay` command, as well as commands based on the same sequencing code (`git history` for example) do not drop custom headers like this, so there is partial non-breakage, but several of the other history editing commands do drop custom headers.

schacon··on Splitting a Git Commit
Well, there are a couple of problems here, if you are interested in an actual answer.

The first is that update-index only works on worktree files, so you need to be actually modifying file contents on disk and then essentially running `hash-object` on them, then `commit-tree`, etc. For an agent, each of these are tool calls and ones that they're not very good at (because nobody really does this manually).

Quick example for clarification. Let's say you want to move half of the changes of a file from one commit to another.

The ideal way would be to run something like:

`git squash <commit-a>:<hunk-id> <commit-b>`

Which could load the tree of commit-a into memory, virtually apply the hunk change to it, calculate the new tree, write it out and rebase the commits - thus moving the hunk. This is what tools like GitButler do with `but squash` etc. One command, pretty simple, all in memory and extremely fast.

The "plumbing" path you suggest would be something like:

- (record patch changes you want) - git reset HEAD~3 - (apply patches you want in commit 1) - git update-index - git commit - (apply patches you want in commit 2) - git update-index - git commit - (recreate the commits above that)

You talk about not interacting with the work tree, but `update-index` directly deals with the working directory. It's just not built for operations like this. It's built for Linus interactively building trees from contents on a filesystem.

schacon··on Splitting a Git Commit
In case you're curious if _you_ can run `git history split`, the answer is almost certainly no, unless you manually installed the newest release of Git within the last 3 months.

`git history` was introduced as an experimental command less than 4 months ago, which means that there are essentially zero OS releases that packages a version that contains it by default. Also, if you're on OSX and run `brew install git`, it will not overwrite the Apple version that is too old to have it.

Git 2.54 was the first release with this subcommand and it is not in Xcode CLT, Debian testing, Ubuntu 26.04 - nothing. It will be "normal" in a year, but it's ridiculous to criticize SO for "old" methods of splitting long before anyone ships with it.

schacon··on Splitting a Git Commit
Not only this, but it's not super simple to update to the newest version anymore. I actually tried this today and I'm on `2.50.1 (Apple Git-155)`. It turns out I don't actually know how to update that. `brew install git` does not overwrite the system binary. I'm not the smartest person in the world, but if I had issues getting to the latest version, I assume a very small percentage of users actually has a Git version that will run `git history`.

It was introduced in 2.54, which was in April of this year, so less than 4 months ago. Almost nobody can run this command unless they're _really_ on top of things.

schacon··on Splitting a Git Commit
Not sure if this is written by an AI, but I'll engage, because it's a bit misleading.

The new `git history` command can take three verbs - fixup, reword and split. While interactive rebasing can do fixup and rewording relatively easily and the `history` variant is a slight improvement, the split sub-subcommand is really _quite_ difficult to do in other Git tooling, including interactive rebase. Before reading on, I would challenge the reader to think about how they might do it.

The answer is that you would rebase back to at least the commit you're splitting, choose 'edit' in the rebase script for that commit (pick the rest), then when the rebase stops there, `git add (-p)` the parts you want, commit, then commit the rest, then `git rebase --continue`. I would guess that maybe 5% of the readers of this paragraph would have guessed that correctly, if I'm being pretty positive.

Patrick wrote the `git history` stuff because tools like JJ and GitButler are pushing UX that makes this type of thing very easy and Git itself is struggling to catch up. Even at a fundamental level, the first versions of history were based on the sequencer code that rebase used but it couldn't do the job properly (messing with the index/workdir), so he rewrote it based on the `git replay` machinery instead (which _itself_ is still somewhat experimental).

Interestingly, it's _still_ not optimized for agents or scripting - `split` specifically needs an interactive terminal like `git add -p` does, so not many agents are good at it. I recently tried it and Claude piped `y\ny\nn` through the command, guessing at the interactive input (y, y, n) needed to stage the hunks.

The point is, interactive rebasing is a horrible solution to this problem, `git history` clearly better, at least for splitting, but really we need non-interactive solutions to problems like this so agents can do them well.

GitButler does this well because we focus specifically on it - our status command gives hunks/files ids and hunk/file movement can happen between commits so splitting is creating an empty commit and then moving the parts over - but it's surprising that nobody else builds tooling for this increasingly common use case.

I think `git history` will slowly get better at this over time, but "interactive rebasing" is a _much_ more error prone and unintuitive way to accomplish this.

schacon··on Billionaire Tax Officially Heads to Nov. 3 Ballot
In California, it's capped at a knowable amount when you buy the home and pegged at the sale price. You know what it is and what it always will be when the transaction happens. The people whom have owned a house now worth a million for 30 years probably pay a few grand a year and always have. Dry taxing the technical value of their assets today would destroy millions of families. The point is that dry taxation is generally pretty stupid.
schacon··on Billionaire Tax Officially Heads to Nov. 3 Ballot
Love it.

In fact, we should have expanded it to be a "millionaire tax" where everyone who has a home worth more than $1M needs to pay a one time $50k+ tax to the highly efficient state government. I'm sure they can easily figure out how to sell a small fraction of their home to cover it.

If there is one thing that history has proven, I think it's how valuable dry taxation is for everyone in the long term.

schacon··on Grit: Rewriting Git in Rust with agents
Relicensing under any other license, including the LGPL, is exactly the same thing. Either the reimplementation copies protected expression, in which case it would be required to be GPL-2.0-only, or it does not, in which case we can choose the most fitting license.

If you believe that using an MIT license is not correct, then you defacto also believe that using an LGPL license is not correct.

schacon··on Grit: Rewriting Git in Rust with agents
> Would you be happy for someone to do the same with the GitButler source code?

Honestly, that would be pretty awesome. We would be flattered.

schacon··on Grit: Rewriting Git in Rust with agents
Nice, I haven't dug into this yet. If we can get this usable, it would be pretty cool to have a small lib or a series of much smaller, directed libs that can be used by simpler interfaces and you can just compose the parts you need.
schacon··on Grit: Rewriting Git in Rust with agents
Not yet. I have a PR with a WASM experiment based on an earlier build, but it's not integrated. It's on my list of things to try. I _did_ get it working for some things, so it's clearly possible, but I need to put some more effort into it.
schacon··on Grit: Rewriting Git in Rust with agents
Well, there's lots of really interesting opinions here from a lot of armchair lawyers.

To clarify, my stance on this is that the reimplementation did not copy protected expressions (Jplag reports less than 1.8% max similarity between the codebases), it's done in good faith, and it's what's best for the broader Git ecosystem (assuming Grit even becomes usable, which it's currently not purported to be).

From a copyright standpoint, however, only the first argument there is relevant. Grit is an independently authored implementation of Git-compatible behavior, with negligible similarity to Git source code.

I think antirez summarized the situation quite well and I broadly agree with his position: https://antirez.com/news/162

I think that those in the community who know me and have worked with me in the Git and open source communities for the last 20 years know that my intentions are to contribute, share and foster innovation and learning. Many of the main authors of the Git source code are friends of mine and I have no intention to steal anything from anyone, only to make their great ideas more broadly useful.

schacon··on Grit: Rewriting Git in Rust with agents
GitButler's source code is available, so we're not asking you to trust us much at all.

https://github.com/gitbutlerapp/gitbutler

schacon··on Grit: Rewriting Git in Rust with agents
A feature complete, reentrant, linkable library. Reading the article often helps with questions like this.
schacon··on Grit: Rewriting Git in Rust with agents
As mentioned, we also work on the Gitoxide project and Byron is a member of our team. We are well aware of all large community efforts and we're also cohosting the Git Merge conference this year.

There is a recent effort to vibe-loop more Git into Gitoxide, which is interesting:

https://github.com/GitoxideLabs/gitoxide/pull/2538

I still think that this is a project that can have value with a little more work. This announcement is merely a milestone, not the end product. I wasn't sure it was really possible to do, even halfway through the project. There has been a lot learned and there is a lot to learn, but I think there are useful applications for both a high quality, hand crafted, opinionated partial Git library (Gix) as well as a vibed, fully implemented, partially sloppy LLM Git library (Grit). We think it's worth exploring and investing in both options for now.

Also, I am the exec involved and I've done quite a lot for the Git community over the years. I would never try to have my "own copy" of it, that's ridiculous. I wrote and open sourced the Pro Git book (https://git-scm.com/book/en/v2) and Git community book before it (https://schacon.github.io/gitbook/index.html), I created the official Git website (https://git-scm.com), I cofounded GitHub which hosts nearly all open source in the world, I have evangelized and supported the Git ecosystem for almost 20 years now. I restarted and funded development of libgit2 15 years ago, which you could similarly argue was an exec trying to have our "own copy" of Git under a more permissive license and would have been a similarly ridiculous argument.

schacon··on Grit: Rewriting Git in Rust with agents
I think Byron (Gix author/maintainer) is one of the most excited people about the Grit project.

Gitoxide is great and we will continue to push it forward. Grit is an orthogonal project. Perhaps we can use one in the other or maybe Grit goes nowhere. But we thought that a small investment in a different approach is worth the effort.

schacon··on Grit: Rewriting Git in Rust with agents
I see it differently. I look at it as if I had written this code myself, using this same approach. Look at the docs, look at the tests, look at the source, implement something that is interactively compatible but a very different approach.

For example, this is exactly what I did when I tried to get SSH commit signing working properly in GitButler:

https://blog.gitbutler.com/signing-commits-in-git-explained

You can see in the post that I dug through the C source to figure out how it was canonically done and then implemented something that accomplished the same thing in Rust but without copying source code.

There are some similarities between the Grit Rust source and the Git source, but it's mostly around time/formatting type things or byte offset type things needed to make packfile parsing and whatnot work, but as far as I can tell, there is no straightforward copying of code. The approach needed to make this a reentrant, memory safe, library driven codebase is so different that copying is generally not useful. But nobody can _guess_ how packfiles or reftable binary formats are specified, since they're not really documented. I'm aware of this because I'm pretty sure I _personally_ am one of the only ones who has ever attempted to document the packfile binary format: https://schacon.github.io/gitbook/7_the_packfile.html

You have to read the source. Which means that libgit2 and Gitoxide and every other Git reimplementation is also "license-washing" per this definition because they also had to reference the Git source to see what the technical specification is.

If you find any code in Grit that is clearly line-for-line copied, please point it out and I will replace it. But the Git source is the Git specification and every reimplementation, LLM or not, is forced to use this approach to build anything compatible.

schacon··on Grit: Rewriting Git in Rust with agents
To be clear, I 100% did not make libgit. I did help the libgit2 project get off the ground.
schacon··on Grit: Rewriting Git in Rust with agents
I'm assuming you didn't read the article, since I'm pretty sure I covered all of this, but I'm happy to respond.

Don't bother.

It's probably not for you. It's slower, more obtuse, more bloated, less capable, exponentially less scalable at any size. Canonical Git is better in every way, except being a linkable library.

Even in the arena of being linkable libraries that can do Git stuff, both Gitoxide (Rust) and libgit2 (C which has git2 crate Rust bindings) are both better, they're just not feature complete. That is the only point of this project.

schacon··on Grit: Rewriting Git in Rust with agents
We're choosing a license that is usable by the entire community. Our goal is a linkable library, which makes GPL impossible. If we had chosen to go with LGPL or GPL with linking exception (like libgit2), it would have the same issue of changing the license, so we went with whatever was the most permissive so everyone could use it for anything if they wish. This has nothing to do with business - I hope I can get the project to the point where Jujutsu or whomever can use whatever is valuable here for whatever they want.

We clearly learned from how Git does operations and emulated it in order to function interoperably, the same way that Gitoxide and libgit2 have, and released it under a license that would be the most valuable for people wanting to use a linkable library, the same way that Gitoxide and libgit2 have.

schacon··on Grit: Rewriting Git in Rust with agents
Gitoxide is also developed primarily by Byron, who also is part of the GitButler team. We're pushing both projects forward.
schacon··on Grit: Rewriting Git in Rust with agents
I'm happy to take contributions if you want to throw some tokens at it. Bug reports would be amazing, since I haven't tested it for real very much (enough to know you can do basics).

I want to get it to the point where we can replace fork/exec'ing to an unknown Git binary or having said binary be an external dependency for GitButler. The networking stuff (push/fetch) is currently an external dep for both GitButler and Jujutsu (and pretty much every other Git-based tool in the world). I'm pretty sure I can get the project good enough at these networking ops (including all the hairy credential stuff) to be able to not need those fork/exec calls.

schacon··on Grit: Rewriting Git in Rust with agents
I started the project as Gust, but felt like Grit was such a better name. I asked Tom if I could boot the name back up again because I always liked it and he said it was fine.

Also, I worked on the Ruby Grit pretty extensively during the early days of GitHub, so hopefully I earned the right to carry on the mantle. :)

schacon··on Grit: Rewriting Git in Rust with agents
I would not use this except to help us test it if interested. I'm announcing it because it's interesting and a milestone in the breadth of test coverage it can pass. It almost certainly cheated on a bunch of those tests and is not feature complete yet.

The author of gitoxide is also working on GitButler (who worked on this project) and we're pushing both projects forward and actively using and developing Gitoxide as well. This is simply a different and hopefully complimentary approach to the same problem.

schacon··on Grit: Rewriting Git in Rust with agents
libgit.a isn't reentrant. It will call `die()` on many errors. If you link to it in a long running binary, it will kill your process on error.

Libgit2 is meant to address this and I was heavily involved in the development of that project 15 years ago. It's great but it's not feature complete and it's development is also completely separate from git development, so it's out of sync and constantly struggling to keep up.

schacon··on Grit: Rewriting Git in Rust with agents
My intent with this project is not to replace Git in any way. I don't care about the CLI part of this project.

The point is to provide a feature-complete reentrant linkable library. Even if it's an ugly and slow one, this is still the only one thing that exists that covers those points - Gitoxide and libgit2 are both awesome but they are not feature complete.

schacon··on Grit: Rewriting Git in Rust with agents
I would also be interested.

I haven't dug into this at all yet, nor have I tried to optimize the size (or really, anything else).

However, the library part will be less than half of this - a lot of code is spent on the CLI specific stuff and would not be part of the library, which is mostly what I care about for the purposes of this project. The CLI part is just to try to prove the point that it actually does what Git does. The library part is what might be useful in that nothing else exists that does all of the things that it does (provide a reentrant linkable library that is feature complete with Git).

schacon··on Grit: Rewriting Git in Rust with agents
It's not for Rust, it's for Library.

Well, it's sort of for Rust. GitButler is written in Rust and Jujutsu is written in Rust and we're both depending on fork/exec'ing to an unknown Git binary with no linkable library and no control over the subprocess to do a range of networking stuff. Neither Gitoxide or libgit2 are capable of this either, as much as I love and support those projects.

This project is entirely about providing a feature complete (even if sloppy) library implementation of Git, which does not otherwise exist.

schacon··on Grit: Rewriting Git in Rust with agents
I addressed this in the post, but Git has no linkable library and never has. If you want to do even something small, you need to fork/exec a process and communicate with it via stdin/out. Or completely reimplement it and all of the edge cases - for example, reading even one object can be either loose (easy) or in a packfile (much more difficult). Reading a reference (what SHA does a branch point to) can be in a loose file, a packfile, or a reftable. etc.

There is no way anyone would ever use this for it's CLI - it will almost certainly always be slower and worse in every way, even if I get it stable (which it's currently not). You can use libgit2 (a project I also helped kickstart), or Gitoxide (a project GitButler also currently helps drive) - they are faster and better in nearly every way, but they are not feature complete.

This isn't for the person using Git. This is for someone trying to build a tool that wants to use parts of Git, which is different.

schacon··on We've raised $17M to build what comes after Git
Git is awesome in lots of ways. As a data storage layer and as a transport protocol, it's pretty great. The porcelain was built for a different era and is slow to adapt. Originally, Git was meant to just be these primitives and everyone was supposed to write their own "porcelain" or SCM on top. We're doing that and then some - creating new standards for more metadata, real time communications, built in review, etc. If anything, we're going back to the original point of git and doing what Linus wanted other people to do in the first place - write a good SCM for their workflows on top of the foundation he started.
← PreviousPage 2 of 10Next →