> That last part goes further than git rebase --update-refs, which only moves refs sitting inside the range you’re actively rebasing. git history instead finds and rewrites every local branch descended from the commit (while also having an option to limit it to only the current branch).
I'm reading that to mean that when I use `git rebase --update-refs` in this situation, where I've currently checked out `D` and update `B` to `B'`:
A ──► B ──► C ──► D
│
└───► E
I'll end up with this state, where `E` remains untouched?
A ──► B' ─► C' ─► D'
│
└───► B ──► E
(EDIT: Originally I had `E` point to `B'`, which doesn't make sense)
If I use `git history fixup`, it would also update `E` and end up with this?
A ──► B' ─► C' ─► D'
│
└───► E'
If that's the case, is there a way to get `git rebase` to have the same behavior? I've got decades of `git rebase` burned into my fingers at this point.
> If that's the case, is there a way to get `git rebase` to have the same behavior? I've got decades of `git rebase` burned into my fingers at this point.
One of the GitHub blog posts of git changelog highlights implied that this new power of `git history` was certainly under discussion for a possible feature addition to `git rebase` but it is partly still a discussion because it is a higher-level function and if the goal is to keep `git history` the "high level" and `git rebase` the "low level" then such features probably make sense to remain only in `git history` for now.
It also sounds like there are camps thinking `git history` is only the learning path to make a better `git rebase` UX and eventually the commands will reconverge somehow.
Both sides of that conversation sound worth exploring to me, and I'm curious to hear how that conversation continues.
Huh.. That's a shame :(. Maybe what it refers to is if you had a branch on B rather than D, it might update that.
EDIT: Yeah, this seems to be it. `git branch b` on b, then `git rebase -i --update-ref @~3` from main caused branch ref `b` to move from d86229e to 02fcaf7:
* 1e354fb (HEAD -> main) fix b
* 40e6f70 c
* 02fcaf7 (b) b
| * f4188e0 (branched-feature) d
| * d86229e b
|/
* 5fe78fa a
It won't result in the third graph on its own as E isn't reachable from D, but it could if you first merged D and E together and then used --update-refs with --rebase-merges. You could then just discard the merged branch and only take care of D' and E' on their own (and since you don't care about the merged branch, you don't have to care about resolving conflicts while preparing it either).
Unless E remained untouched because it was not rewritten, and ended up staying parented on B instead of getting reparented onto B'.
Which is usually not what you want; most of the time you want E', which is E reparented onto B'. But sometimes you want E to remain untouched and stay parented on the original B. Depends on the situation.
I'm not sure that answers my question. That shows a linear set of branches (my-feature-v3 depends on my-feature-v2 depends on my-feature-v1 depends on main). I'm asking about the case where two or more branches fork from a common ancestor and you want to fix the common ancestor.
I tend to write most of my async Rust following the actor model and I find it natural. Alice Rhyl, a prominent Tokio contributor, has written about the specific patterns:
Oh I do too, and that's one of the recommendations in RFD 400 as well as in my talk. cargo-nextest's runner loop [1] is also structured as two main actors + one for each test. But you have to write it all out and it can get pretty verbose.
The ‘Beware of cycles’ section at the end has some striking similarities with futurelock avoidance recommendations from the original article… not sure what to make of this except to say that this stuff is hard?
You certainly can use thiserror to accomplish the same goals! However, your example does a little subtle slight-of-hand that you probably didn't mean to and leaves off the enum name (or the `use` statement):
- You don't need to move the inner error yourself.
- You don't need to use a closure, which saves a few characters. This is even true in cases where you have a reference and want to store the owned value in the error:
#[derive(Debug, Snafu)]
struct DemoError { source: std::io::Error, filename: PathBuf }
let filename: &Path = todo!();
result.context(OpenFileSnafu { filename })?; // `context` will change `&Path` to `PathBuf`
- You can choose to capture certain values implicitly, such as a source file location, a backtrace, or your own custom data (the current time, a global-ish request ID, etc.)
----
As an aside:
#[error("failed to open a: {0}")]
It is now discouraged to include the text of the inner error in the `Display` of the wrapping error. Including it leads to duplicated data when printing out chains of errors in a nicer / structured manner. SNAFU has a few types that work to undo this duplication, but it's better to avoid it in the first place.
I do too! I've been debating whether I should update SNAFU's philosophy page [1] to mention this explicitly, and I think your comment is the one that put me over the edge for "yes" (along with a few child comments). Right now, it simply says "error types that are scoped to that module", but I no longer think that's strong enough.
I accept, however this requires to create many types with corresponding implementations (`impl From`, `impl Display`, ...). This is a lot of boilerplate.
In addition to the sibling comment mentioning thiserror, I also submit my crate SNAFU (linked in my ancestor comment). Reducing some of the boilerplate is a big reason I enjoy using it.
As we all know, Cool URIs don't change [1]. I greatly appreciate the care taken to keep these Compiler Explorer links working as long as possible.
The Rust playground uses GitHub Gists as the primary storage location for shared data. I'm dreading the day that I need to migrate everything away from there to something self-maintained.
I hope to read through your crate and examples later, but if you have a chance, I’d be curious to hear your take on how Stack Error differs from my library, SNAFU [1]!
I played around a bit with SNAFU a couple of years ago, but I'm haven't worked deeply with the library so there might well be some features I'm not aware of.
I think SNAFU is more like a combination of anyhow and thiserror into a single crate, rather than Stack Error which leans more heavily into the "turnkey" error struct. Using the Whatever struct, you get some overlap with Stack Error features:
- Error message are co-located.
- Error type implement std::error::Error (suitable for library development).
- External errors can be wrapped and context can easily be added.
Where Stack Error differs:
- Error codes (and URIs) offer ability for runtime error handling without having to compare strings.
- Provides pseudo-stack by stacking messages.
Underlying this is an opinion I baked into Stack Error: error messages are for debugging, not for runtime error handling. Otherwise all your error strings effectively become part of your public interface since a downstream library can rely on them for error handling.
Here's a leaked / rumor image of Apple servers themselves.
https://www.macrumors.com/2026/08/26/leaked-images-of-apple-...