Hacker News new | ask | show | jobs
by kipari 2085 days ago
I enjoy how well-crafted Fossil seems to be; just like SQLite, which a sibling comment also mentioned. I really want to use Fossil, but it would be way too hard for me to not have the index/staging area of Git. [1] For all the software that claims to be 'opinionated', Fossil really is that.

[1]: https://fossil-scm.org/home/doc/trunk/www/gitusers.md

3 comments

Yes. I use `git add -p` and `git stash -p` all the time and couldn't work without them. Fossil's equivalents appear to let you specify a subset of files to commit / stash, but not individual thunks inside them. [1] [2]

Not to mention the lack of `rebase -i` to clean up local commits.

[1]: https://www.fossil-scm.org/fossil/help?cmd=commit [2]: https://www.fossil-scm.org/fossil/help?cmd=stash

It would seem the authors consider rebase harmful: https://fossil-scm.org/home/doc/trunk/www/rebaseharm.md
I'm sympathetic to a lot of what they have to say, but this has always been a sticking point for me:

> Cherry-picks work better with small check-ins

Maybe it's just bad git tooling or me using the tools wrong, but if I need to cherry-pick and there are conflicts, it is always way easier to squash everything down and pick it in one go— if I don't do that, I end up resolving the same conflict over and over as new commits pile in on top of it and meet a conflict-resolved state that they then have a further conflict with.

The author of pijul is of the opinion that cherry-picks only work in accordance with the developer's mental model, if the VCS is based on patches.

I've been persuaded by his argument, and I'm really looking forward to the pijul rewrite landing, so I can play around with it again.

> if I don't do that, I end up resolving the same conflict over and over

You should check out git rerere.

https://www.git-scm.com/book/en/v2/Git-Tools-Rerere

Interesting, thanks for that! Will try in the future.
I don't cherry-pick much in git, but I'm guesing rerere doesn't work with it?
I think it probably would for at least some cases, and I'll give it a try definitely.
Contrary to that article, squashing aids bisection rather than hurts it.

One simple example:

commit 1: things work

commit 2: Feature X, regress

commit 4: Feature Y, break things by accident

commit 5: oops, fix commit #4

...

You land on commit 4 breaking your commit, but if #5 and #4 had been squashed then you would find commit #3 much more easily.

With a tiny history like this it's not a big deal, but with a larger one, it becomes an issue.

On personal projects (using git), I use squashing only for small bug fixes like the one you mentioned or when the author of a PR made a big mess of commits (usually because they are a git beginner). Best of both worlds.
Do you not make a big mess of commits, then selectively squash before submitting a PR?
I don't see why you would bisect in this situation in the first place. The problem's fixed now, as of commit 5.

But okay, let's take your example as-is: you determine the "good" point is commit 1, and the ...um, other good point is commit 5?

Well, that doesn't work. I guess we have to arbitrarily ignore commit 5 and say commit 4 is bad. A bisect will show that. Then in Fossil, if you visit the /info page for commit 4, it will show its child commit 5 as fixing the problem.

Try again. Squashing doesn't solve anything here.

I'm rebasing because the problem from commit #2 isn't fixed. We have a test that shows the problem from commit #2. However commit #4 breaks things in some way that the test we are running can't run. Squashing the commits together fixes this. If commits #4 and #5 were both on a feature branch before merging, squashing would be done by rebasing in the feature branch.

I'm not saying all commits from a feature branch should be squashed to a single commit, but commits like "oops forgot to update header file" or some such are noise.

Rewriting history is about improving the signal-to-noise ratio. You may lose some signal (the Fossil argument against it), but if you lose more noise than signal it may be worth it (the git argument for it).

(Holy shit I didn't realize how long this had gotten.)

I read that page. It's their opinion and I disagree with it.

To be clear of where I'm coming from, I've never used fossil, and I've used git regularly for about 10 years. I only use git from the commandline except that I often use `gitk` to read a branch's commit history or inspect diffs, and I use `kdiff3` for interactive merging when there are conflicts. I actively disable git "integrations" in editors and IDEs.

---

>1.0

Whether other people struggle with rebase or not does not affect me, because I have no problems using it. (This logic also extends to people who complain the entire git CLI is hard to use.)

Now, this might sound like the seasoned C programmer saying "Other people accidentally write UB but I don't, so C is perfectly fine." but there is a difference. UB with C is problematic because it's hard to know it happened, which is why we know the seasoned C programmer might have unknowingly written UB after all. This is not the case with `git rebase` though. Either you do it correctly or you don't, and I can confidently say I do it correctly.

>2.1

This is specifically talking about rebases that move commits onto new parents. Rebase does much more than that. For this particular use case, I agree that some projects even when using git prefer to have merge commits instead of rebased commits, and that's fine. But for projects that do want a linear series of commits, it's good to have the choice. Rebased commits also make it easier to revert just a single commit instead of the whole merge (though of course it's not impossible to revert a single commit of a merged branch either).

>2.2

This whole section is a non-sequitur because indeed the correct pre-rebase diff would indeed be diff(C2, C5) even in the git case. But if you're planning to rebase the code in order to merge it, you need to rebase the code to know what the diff will be.

>3.0

The Windows Vista citation starts off with the (correct) result that lack of communication between engineers of disparate components leads to bugs, but then associates it to mean that these disparate components were being developed in private branches. The cited paper does not talk about branches at all. Indeed, bugs happening because of private branches was not the case then, and is not the case now. The reason those bugs happen is because the engineers of a particular component only work with code of their component.

The "egoless" citation is from a book, so I can't tell if the book specifically says private branches have anything to do with ego or not.

At any rate, this section is fundamentally confused. Making branches public doesn't mean you can't rebase them. If I work on an OSS github project, I would certainly make my WIP code branch public. That doesn't mean I don't want to rebase it right before I send a PR to clean the cruft up.

I think the article author may have read the git advice about not rebasing public branches and thought it meant all non-private branches. It actually means branches other people would want to pull from you and who are not expecting it to be rebased. Single-person development happens in branches only that single person cares about, so whether the branches are private or public makes no difference to that person wanting to be able to rebase them. If a group of people are collaborating and they agree that rebases are going to happen, nothing is wrong with letting them do that. The only problem is with rebasing public branches that people pull from and which those people do not expect to be rebased, like a public repo's `master`.

>4.0

So test each commit then. git doesn't makes it impossible to do that or anything. If anything, ensuring tests pass on each intermediate commit makes `bisect`ing easier in the future.

Also, only using merges means the only tested commit is the merge commit, so you lose the ability to check which commit in the merged branch caused the problem.

See also 7.0

>5.0

`git rebase --ignore-date` will reset the commit date of each rebased commit to the current time.

>6.0

It is correct that commit messages are the only way to associate some of the metadata that Fossil lets you manipulate separately. So (2) and (3) do benefit from Fossil's approach.

(1) and especially (5) happens rarely enough in my experience that it isn't enough justification.

I'm not sure what (4) is referring to by "routine display", but in general the only branches things like `gitk` will show you are the ones you ask for.

>7.0

It also throws away non-valuable garbage. When I'm bisecting a bug, or running a `blame` to figure out what commit added a particular line, I don't need to go through half-commits that got reverted afterwards.

False starts and incorrect approaches can be documented in the commit message or in the code comments.

Also this directly contradicts 4.0 unless we are to assume that only merge commits get tested, and that the user running `blame` does not go deeper than the merge that introduced the line, which has the problem I mentioned in 4.0

>7.1

This section is just a longer reiteration of 7.0, so it has the same rebuttal.

>7.2

This has switched to specifically talking about squash rebases, which is not necessarily the only kind of rebase (and is also not the kind of rebase that the diagram in 2.2 was talking about). I also dislike squashed rebases when merging pulls. But if I have to squash two commits in my WIP branch I absolutely want to be able to.

>7.3

If the checkins are being rebased and are going to be merged without squashing, then each commit has to stand on its own by definition, so of course they should all have individual justifications.

>7.4, 7.5

These are the same as 7.2 and 8.0 below.

>8.0

This appears to be saying that fossil's cherry-pick is not just a wrapper around rebase like git's is. So I agree that (1) and (4) are benefits due to Fossil's approach.

(2) is exactly the same as 4.0

I don't understand what (3) is trying to say.

> Windows Vista...components were being developed in private branches.

The claim isn't that Microsoft developers on the Vista project used Git and private branches. The claim is that private branches are another form of siloing which leads to the same sorts of communication problems. They're a way to purposefully hoard code so your fellow developers can't see it. It is exactly what McCarthy was warning about in his "beware a guy in a room" comment; and McCarthy was at Microsoft when he wrote the book cited.

> I can't tell if the book specifically says private branches have anything to do with ego or not.

Weinberger wrote his seminal book in 1972, so probably not. :)

Human psychology hasn't notably changed since 1972. It doesn't matter if you're developing with punched cards or with worldwide Kubernetes clusters, humans are humans.

> Single-person development happens in branches only that single person cares about, so whether the branches are private or public makes no difference to that person

If you're doing single-person development, then the concerns over siloed development don't apply at all.

This section of the document is talking about communication among developers on the same project. If there is no communication on your project, its points are irrelevant, not wrong.

>4.0...So test each commit then.

You're missing the point. If Fossil offered Git-style rebase, the commit would be pushed up to the remote repo you cloned from before you could possibly test it, because of its autosync feature.

The autosync feature and the practice of leaving it enabled as much as possible is justified here: https://fossil-scm.org/fossil/doc/trunk/www/fossil-v-git.wik...

> `git rebase --ignore-date` will reset the commit date

How often do you suppose that's done in practice?

The point in the article you're rebutting is that Fossil doesn't make you do that at all, because it doesn't create timewarps or require after-the-fact date rewrites to avoid them.

> I'm not sure what (4) is referring to by "routine display"

It refers to the "fossil amend COMMITID --hide" feature. Affected branches no longer show up in the timeline, in the default branch list, etc., but no info is destroyed. It's just a tag telling the web UI and CLI not to show that branch by default.

> I don't need to go through half-commits that got reverted afterwards.

You're assuming 20/20 foresight. The very nature of software bugs is that you don't know you're committing them at the time, so how can you prospectively know which elements of a commit are good and which bad? You can mitigate it through testing, code review, etc., but Bugs Happen. There are whole companies dedicated to that fact.

The very point of bisect is, "Given this pile of commits between points GOOD and BAD, which one caused the symptom I'm seeing now?" If you knew the answer to that, and thus were able to make the in-advance judgement you suggest, you wouldn't need to do the bisect, because you wouldn't have committed the bug in the first place.

> this directly contradicts 4.0 unless we are to assume that only merge commits get tested

Only if you assume you have 100% test coverage, both in terms of lines of code and functionality. If you are in such a happy position, and you always run your tests before committing, then yes, it is impossible to commit a bug to the repo.

I wanna see that repo, the one without bugs because it has 100% functional-test coverage.

Even SQLite hasn't got that, evidenced by the fact that its test suite continues to change, even for historical features.

> If I have to squash two commits in my WIP branch I absolutely want to be able to.

You're toggling between "have to" and "want to".

And again, you're assuming 20/20 foresight, that you will never want to come back and tease those commits apart again.

The merge point is the proper place to logically "squash" things, not within the WIP branch.

>The claim is that private branches are another form of siloing which leads to the same sorts of communication problems. They're a way to purposefully hoard code so your fellow developers can't see it.

This is such a painfully armchair-psychologist point of view I don't even want to attempt to disprove it.

But consider this: if committing in fossil makes your code immediately visibile to the world, and if we are to assume the people using git want to hide their "imperfect" code in those evil bad private branches (even though, as I wrote in my comment, the whole private-vs-public distinction is irrelevant), one must assume those same people using fossil will also want to hide their "imperfect" code too. Doesn't that mean people using fossil will just commit less frequently?

---

>> Single-person development happens in branches only that single person cares about, so whether the branches are private or public makes no difference to that person

>If you're doing single-person development, then the concerns over siloed development don't apply at all.

>This section of the document is talking about communication among developers on the same project. If there is no communication on your project, its points are irrelevant, not wrong.

Please read the next sentence I wrote right after where you stopped quoting.

---

>>>4.0...So test each commit then.

>You're missing the point. If Fossil offered Git-style rebase, the commit would be pushed up to the remote repo you cloned from before you could possibly test it, because of its autosync feature.

Okay, so it's a fossil-specific problem with a hypothetical fossil-rebase implementation, not a problem with git-rebase, unlike the rest of the page that's pointing out problems with git-rebase. I'm sorry for "missing the point".

---

>> `git rebase --ignore-date` will reset the commit date

>How often do you suppose that's done in practice?

>The point in the article you're rebutting is that Fossil doesn't make you do that at all, because it doesn't create timewarps or require after-the-fact date rewrites to avoid them.

If the repo is on Github and the PR is being merged through its web interface, that is one of the default merge options the repo admins can set.

In other cases, the person doing the merge can remember to use it.

Many options have defaults that can be configured, and this isn't one of them. So either nobody has implemented it yet, or the occurrences of time travel in a linear history hasn't bothered enough people yet. I suspect it's the latter.

---

>> I'm not sure what (4) is referring to by "routine display"

>It refers to the "fossil amend COMMITID --hide" feature. Affected branches no longer show up in the timeline, in the default branch list, etc., but no info is destroyed. It's just a tag telling the web UI and CLI not to show that branch by default.

Okay, so it's not related to rebase then, in git or otherwise.

---

>> I don't need to go through half-commits that got reverted afterwards.

>You're assuming 20/20 foresight. The very nature of software bugs is that you don't know you're committing them at the time, so how can you prospectively know which elements of a commit are good and which bad? You can mitigate it through testing, code review, etc., but Bugs Happen. There are whole companies dedicated to that fact.

I don't think you understood the situation I wrote about. I'm talking about using blame or bisect to go through the history of code that has already been committed, trying to find the source of a line of code or a bug.

See https://news.ycombinator.com/item?id=24643869 for an example.

---

>> this directly contradicts 4.0 unless we are to assume that only merge commits get tested

>Only if you assume you have 100% test coverage, both in terms of lines of code and functionality. If you are in such a happy position, and you always run your tests before committing, then yes, it is impossible to commit a bug to the repo.

There is no such assumption in what I wrote.

---

>> If I have to squash two commits in my WIP branch I absolutely want to be able to.

>You're toggling between "have to" and "want to".

The sentence I wrote is both grammatically and semantically correct. It would not be correct to use two "have to"s, nor would it be correct to use two "want to"s.

---

>And again, you're assuming 20/20 foresight, that you will never want to come back and tease those commits apart again.

>The merge point is the proper place to logically "squash" things, not within the WIP branch.

Listen, if I have a commit:

    bar the foo

    +    foo.bar()
and then another:

    derp

    -    foo.bar()
    +    foo.bar();
... then I'm very confident I want to squash them together, thanks. I'm also very confident that when I send a pull request, I want the commit to read

    Invoke bar on the foo object before it's baz'd, otherwise foo is in an undefined state.

    Fixes #3

    +    foo.bar();
> one must assume those same people using fossil will also want to hide their "imperfect" code too

One must not, because if one did, one would be wrong. :)

Go read Weinberger. It's $10 on Kindle right now.

> Please read the next sentence I wrote right after where you stopped quoting.

First, don't assume that because I didn't quote your posting in full that I didn't read it in full. HN is a threaded messaging system: we don't need to fully quote everything just to maintain the flow of the conversation. The history is right there to see on the page.

Second, how does "If a group of people are collaborating and they agree that rebases are going to happen, nothing is wrong with letting them do that," argue against the article in question? That's just a blind assertion, not logical argumentation.

> not a problem with git-rebase,

Sure it is: if rebase commits a breaking change to the blockchain immediately because you weren't able to test it, you have two options: 1. Commit a fix, pushing the broken commit later, potentially breaking bisect and such. 2. Do more rebase squashing and such to fix it in place before pushing it.

Argument 2 is "We need rebase because we used rebase." :)

Fossil's alternative is to not commit anything to the blockchain automatically. If Fossil did have rebase, it would make the changes in the checkout tree only, and you'd have to commit it separately.

The argument is not "Fossil can't have rebase because Git's version is badly considered," it's "Fossil's developers don't want rebase and Git's version is badly considered anyway." Fossil could avoid the design error, but that doesn't make rebase a good idea.

> If the repo is on Github and the PR is being merged through its web interface

...then you're using proprietary software with tremendous lock-in, but okay, if you're willing...

> the merge can remember to use it.

You're really going to insist on that? Commands by the foot, instead of a sensible default?

> it's not related to rebase then, in git or otherwise.

It's an example. The argument we've received multiple times from Git fans is that developers need rebase to make the timeline "clean", but Fossil shows that you don't have to modify history to do that. You just need sufficiently powerful tools that let you preserve history while changing its presentation to the user to suit various needs.

Git's porcelain is showing here.

> derp... - foo.bar() ... + foo.bar();

So you've committed without compiling first, much less running the tests, and your solution is "I need rebase?" No, my friend, you need to compile and run the tests before committing!

Maybe you want a better example?

Agreed. I'd love to have integrated bug-tracking, and some of the other features, but Fossil is also trying to drive particular opinions about version control that are incompatible with how many people want to work.

It's already hard to move people away from a system that has huge network effects. This makes it much harder.

There are several bug tracking systems that store their data inside the repository (and as a result, branch / merge / push / pull automatically) -- including the venerable "vi bugs.txt" system which works surprisingly well from experience.

What fossil brings that those systems don't is indeed the network effect as you pointed out. It's integrated with the web frontend, and is thus used by everyone using fossil and fossil's bug tracking, based on experience with cvstrac, is low ceremony, easy to use and reasonably effective -- even more than "vi bugs.txt" which sets a remarkably low ceremony bar.

That's exactly what I'd love to have, just without the opinionated differences in things like rebase, staging, branching, and similar.
Where did you see opinions in that document? It's a technical description of the functional differences between Fossil and Git, explained with Git terminology.