A bit like having a word processor with a “format” command that changes text font, but is also used to produce a word count or print the document.
I think it attracts so much attention because git is forced on people by network effects, but many think the inconsistency of its interface defies belief, and that this lack of empathy for the user is symptomatic of a broader problem in designing software that seems to be prevalent across our industry.
The OXO brand of kitchen utensils was designed for people with arthritis. It became a giant worldwide brand because people realized that utensils that felt good for people with arthritis also felt good for everyone else.
Not everything is a tradeoff. Sometimes we can just do better.
I haven't used Hg, but I'm guessing it doesn't have anything as bad as checkout.
Mercurial indeed lacks a staging area
> the notion of committing locally and pushing remotely would be fundamentally different
If you enable phases, it does. By default, all local commits are "draft" commits, which can have history edited. But when you push to (or pull from) a public repository, it becomes a "public" commit, and Mercurial will refuse to edit those commits. There's also a "secret" phase, which Mercurial will refuse to push to a public repository. You can also configure whether or not remote repositories are public or not.
The other fun feature is changeset evolution: when you rebase a changeset, Mercurial will keep the original changeset around with a link between the old and new versions of it. If you push the rebase remotely to a repository that previously had the original, Mercurial will tell people that changesets based on the original also need to be rebased when they pull it, and the history information will let them use the regular rebase flow to do it. Too bad BitBucket is dropping hg repos...
I'm sure someone will dispute that it is the same as the staging area, but mercurial does have the ability to only include some things in commits, and I use it daily. I admit I have no idea how it works on the command line, but in tortoisehg I can select individual files and hunks thereof to add to a commit (screenshot: https://imgur.com/ErPEjSN).
It's my impression that loads of people use this feature and somehow don't notice it exists, and will openly agree that mercurial lacks a staging area. My opinion is that defaulting to including changes from all files previously committed is such a sensible default that it makes the feature so seamless that people forget it exists even whilst using it.
Kinda like how people from the US think you can't turn left on red in Australia (equivalent of right on red in the US). You can, but the existence of slip lanes everywhere its allowed mean you don't actually face the red light when doing so. This hides it so effectively that I've seen several people complaining that they can't turn on red, not noticing that they do it every day.
What Mercurial doesn't have is a separate repository concept of an incomplete commit that has awkward, and often inconsistent, interactions with several common repository commands. Git has this, and this is the staging area.
The UI feature you use has nothing to do with the staging area, and is in fact closer to the `hg commit -i` interactive commit mode.
I find this quite handy in Mercurial, as I sometimes realise while writing the commit message that e.g. I forgot to remove a line of temporary debug output, and I can still go and do it before I save the commit message. But that's very bad form that reflects badly on me. The way Git does it feels more correct.
So do p4 and svn, through "changelists". The difference is that only in git is the staging area "persistent" from one command to another, and hidden from you when you run the default "what are the differences between my working directory and the head" command.
Mercurial has a very good extension system, and ships several useful extension in the default installation. The 'record' extension adds the 'commit individual hunks' functionality of the git staging area, and needs a one line "record=" in your config file to enable it. See: https://www.mercurial-scm.org/wiki/RecordExtension
By having some of these functionalities in extensions, the core interface is kept simpler and easier to learn, but the more powerful features are still there for those who want them.
Perhaps this:
* https://www.mercurial-scm.org/wiki/GitConcepts#Git.27s_stagi...
For the most part, you can do anything with either one that you could do with the other, and the practical differences are mostly just in the UI, as well as a cultural component (e.g. hg more strongly discouraging history rewriting is part UI, part culture). Personally, I prefer the git UI because it has a more direct mapping onto manipulating a DAG of commits, but obviously not everyone feels that way, and I don't expect them to. When I first started with DVCS, I started with hg since it seemed easier to learn.
(Although really, my DVCS UI of choice is Magit, which I use for 99.9% of git stuff, to the point where I almost never need to actually run git myself on the command line.)
Queues?
* http://stevelosh.com/blog/2010/08/a-git-users-guide-to-mercu...
That would be a leaky abstraction. The fact that is using DAG should be irrelevant. If they find a better way of doing the work, that shouldn't really affect the ux.
- [Major] I feel (but could be potentially convinced otherwise?) that there is one very deep fundamental flaw in the semantic model, and that is the fact that the identity of a commit depends on its history. I simply do not understand why this has to be the case. If I later discover a ZIP backup of the tree that I forgot to commit, and I want to insert it into the history, it shouldn't suddenly completely break the entire repo. Of course it seems fine to have a hash that depends on the history, and it's very likely useful for many purposes, but that shouldn't be the primary mechanism for identifying commits. By default, I think the identity of a commit should be defined by a hash of its contents only, but independent of its history. This would (among other things) let you re-write the history structure without rewriting the commits themselves and causing other people to have to reset their repos, which seems insanely useful to me.
- [Minor] I wish metadata was also preserved.
If you just hashed diffs, you would not get whole-repo integrity guarantees.
It is possible to go the other way with patch theory (see Darcs) but it's far from trivial to implement performantly.
Yes, of course I realize that's the reason. My entire point was that a commit shouldn't represent the entire state of a repository.
> Being able to take a sequence of commits and insert them into a repository just is not a thing that makes sense in git's model.
Yes, and this is exactly why I declared this to be a fundamental flaw in git's model.
> If you just hashed diffs
Diffs are an implementation concern, which I don't care about. I'm only talking about the logical semantics.
> you would not get whole-repo integrity guarantees.
As I explained, I wasn't suggesting you must get rid of that hash entirely: "Of course it seems fine to have a hash that depends on the history, and it's very likely useful for many purposes, but that shouldn't be the primary mechanism for identifying commits."
> It is possible to go the other way with patch theory (see Darcs) but it's far from trivial to implement performantly.
Again, I didn't say you have to get rid of the current hashes. I was just saying we need something else to use for identifying commits.
------
If an example helps: consider what happens when you (say) sign off on a commit. Are you genuinely signing off on the history? Can you even claim with a straight face that you even know everything in the history behind every commit you sign off on? The reality is, you don't, and you don't need to, because you're only concerned about the commit itself. There's no reason a change in history should invalidate your signature. (Of course, the point here is not just signatures. They're just one example to illustrate what I'm saying. You can think of other scenarios.)
No, you are signing off current state of the repository. Otherwise it would be possible (not trivial, but possible) to take signed commit and apply it on different history, which could create a security loophole.
Your view on commit is a logical set of changes. Git's view is state of the repository. The set of changes between revisions, which is useful for developer to see more than the whole state, is computed on the fly.
>I was just saying we need something else to use for identifying commits.
The commit message?
No, my view of a commit is not a logical set of changes. It's everything that would be in my worktree if I checked out the commit. Which is neither merely the changes from the previous commit(s), nor the entire history leading to the current commit.
But I don't think it's literally as simple as just taking the commit metadata and slapping it onto the tree objects.
I spend some time thinking about and I couldn't come up with anything sensible which wouldn't lead to history being effectively brokenm
To my mind It would be akin to walking across the room and then somehow changing things such that you took one step fewer than required.
I'm not sure what kind of implementation you're envisioning that could work the way you seem to describe. Or do you mean that git should save the entire state of the repository as independent blobs every time you commit something? I don't think you could do that with any hope of reasonable performance.
If you instead just allowed "removing" commits logically without actually physically altering the datastructure on disk, there's no point in providing the functionality in the first place.
Yes
> there's no point in providing the functionality in the first place.
Why so dismissive? Wouldn't it make sense to give me the benefit of the doubt here and ask me what the point of something like this might be, instead of just shutting down it down as pointless? Unless you think I'm just dumb, or otherwise trying to troll here by asking for something pointless?
I think there is plenty of point in doing so. I gave just 1 example on the bottom of this comment: https://news.ycombinator.com/item?id=21395437
Git doesn't try to hide the fact that the committed data is immutable, and to accomplish "deletion" the only option is to rewrite the entire affected part of the datastructure and garbage-collect anything that's unreferenced. You can not modify a commit. You can only create new commits and manipulate references to them.
This is fundamentally what enables git to function in a distributed manner, since the only state between repositories that needs special logic are the references; the actual data could be blindly synced with rsync or something, because it practically speaking can't ever conflict.
In order to have useful global non-hash commit identifiers, you would need a separate data structure of references that somehow decides which commits are identical, and is capable of reconciling conflicts globally across all clones of a git repository. I'm pretty sure that this isn't even in theory possible for the general case.
As for signoffs, a change in history might make a change you signed off broken or completely irrelevant, so yes, I do think that a change in history can invalidate a signoff on a commit.
I think this is sort-of how Pijul and, earlier, Darcs work (https://pijul.org/)
This is a common misconception that is corrected in many blog posts and tutorials; it's also explained clearly in the documentation. See the section (aptly) titled "Snapshots, Not Differences", where it says [1]:
"The major difference between Git and any other VCS (Subversion and friends included) is the way Git thinks about its data. Conceptually, most other systems store information as a list of file-based changes. These systems (CVS, Subversion, Perforce, Bazaar, and so on) think of the information they keep as a set of files and the changes made to each file over time. [...] Git doesn’t think of or store its data this way. Instead, Git thinks of its data more like a set of snapshots of a mini filesystem. Every time you commit, or save the state of your project in Git, it basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot."
Now of course as an implementation detail it only stores diffs based on existing blobs, but except for the obvious speed difference, this fact is completely irrelevant to you as a user. You neither know nor care how it is actually storing its commits. And the thing is, even if you looked underneath, you would have absolutely no guarantee that the blobs are physically stored as diffs against the parent commits. They might be stored as diffs against other random blobs the repo for efficiency, and the user would be none the wiser.
[1] https://git-scm.com/book/en/v1/Getting-Started-Git-Basics#Sn...
I know that is true of Git - that's why I thought that that was what you were complaining about.
Commits whose identity does not depend on their position in history are commits that are commutative (with respect to their position in history). So you very much said so, but we obviously appear to be talking about different things. I'm at a loss as to where these things differ.
I agree the concept of a standalone snapshot is useful, but I don't think snapshots are the right abstraction when thinking about the evolution of a codebase from a human perspective and consider changes the more important concept.
But I never said changes aren't important and should be neglected. And I'm also not saying there shouldn't be any relationship about commits' relationships to each other. You certainly can and should record and utilize that information as well. It just shouldn't be part of that commit. (Except maybe if it's a merge commit, in which case the contents of the previous file system snapshot are relevant. But even there, that shouldn't include the hash, which represents all the ancestors.) Information about commits' relationships should be external information, whose manipulation won't suddenly alter the commits or their identities themselves.
This isn't a radical proposal or something. For starters, git's own documentation (which I already linked here) literally say "Git thinks of its data more like a series of snapshots of a miniature filesystem". Well, the snapshot of the file system doesn't include the history of how it came into creation, so doesn't that mean that shouldn't be part of your commit? That's already a contradiction with its own principles right there. And going beyond that, most things we do with commits already revolve around the file system snapshots, not the history. e.g. when you sign a commit, you sign the snapshot, not the history. Or when you say this guy is the "committer", you're just talking about the snapshot, not the history. And when a commit gets inserted into the middle of the history, that logically doesn't affect you, and in practice, you don't want it to trash the commit you're one. The identity of your commit is still the same after all -- it's the same snapshot.
git checkout somefile (revert a file) -> hg revert
git checkout somebranch (switch to a branch) -> hg update somebranch
git checkout -b somebranch (create a new branch) -> hg branch somebranch
The first one is selecting a subset of the repository, exactly one file, and making the filesystem copy contain the contents that are in HEAD.
The second one makes the whole repository look like a different branch.
The third is just the second, along with a branch operation (which is weird to combine in it).
I’ll agree with you, though, just for a different command: git reset. That is a command that truly can’t be described in one sentence.
If there was a command line tool for Taylor's theorem,I would prefer the one with generalized interface instead of the one that arbitrarily decided that n=1 was the standard case.
https://www.joelonsoftware.com/2001/04/21/dont-let-architect...
> When great thinkers think about problems, they start to see patterns. They look at the problem of people sending each other word-processor files, and then they look at the problem of people sending each other spreadsheets, and they realize that there’s a general pattern: sending files. That’s one level of abstraction already. Then they go up one more level: people send files, but web browsers also “send” requests for web pages. And when you think about it, calling a method on an object is like sending a message to an object! It’s the same thing again! Those are all sending operations, so our clever thinker invents a new, higher, broader abstraction called messaging, but now it’s getting really vague and nobody really knows what they’re talking about any more. Blah.
Both mercurial and subversion have update do the same thing (update the working copy to be the same as the one stored in the source control), and a revert verb (revert a file in the working copy to be the same as the one in the source control). Cvs and git instead use a single verb (update/checkout) for updating the entire tree or a set of files to a given revision. Interesting!
Your third git example above just combines those two operations into a single command as a convenience.
For example, the equivalent of git fetch (fetch remote code without updating the working copy) is hg pull, while the equivalent of git pull (fetch remote code and update the working copy) is hg pull -u (pull, then update).
In my opinion, and this can be debated, is that it makes more sense to attach it to the first operation, since one would look at the documentation of the first command (how do I fetch the remote code?) then see that the working copy can be updated as part of that. The git documentation does mention git checkout -b as part of the git branch documentation, though.
Maybe this is just a rant against git though, at the end of the day, as long as work gets done, use whatever tools work for you. :-)
And therein lies the problem. Ambiguous commands are not good for UX.
I'm not sure what's so confusing about it. Are people thinking of their entire git workdir as the repository? I suppose the fact that .git is often in the same directory as the checkout might lead to people not thinking of them as separate entities.
And updates the index. And sometimes it gets files from the index instead of a commit.
From a workflow perspective, "switch to working on a different branch", "copy some files into the working tree from a different commit", and "resolve all merge conflicts in this file in favor of 'ours' or 'theirs'" are three very different operations. From a low-level perspective they're somewhat similar, but not the same.
Not quite accurate. From the root of the repo, `git checkout foo -- .` will checkout the entire contents of the branch without updating HEAD.
It checks ou a version of the repository from a specific point in its history?
That is one of the things checkout can do, if you pass it a commit hash as the only argument. If you pass it a branch name, it does something quite different (a branch does not represent a specific point). If you pass it the path of a file, it does something quite different again. And depending on what extra flags you pass it, it'll do different things again, including creating a new branch, which is entirely different again.
No, that's all that git checkout does: check out prior commits.
Passing a branch name actually points to the branch HEAD, which marks a specific commit made in a specific point in time.
Passing a tag also does the same thing: check out a specific commit.
Passing a file path does the exact same thing: check out the contents of a specific file as saved in a specific commit represented by the branch HEAD. It's the exact same thing as git checkout <branch> or git checkout <tag>, except it does not update the whole working copy.
> And depending on what extra flags you pass it, it'll do different things again, including creating a new branch, which is entirely different again.
That's false as well. Running git checkout -b may be syntactic sugar for git branch && git checkout but what you are asking git to do, again, is to checkout a specific commit that represents the state of the repository at a specific point in time. That's it.
All git does is enable users to navigate and edit a graph of commits. It takes a poor mental model of git and a poor understanding of what git does to fail to understand that all git checkout does is checkout a commit done somewhere in the past.
But imagine bringing a book to a librarian and saying "hello, I'd like to checkout this book" and the librarian says "ok" and snatches the book from your hands and throws it into a furnace and tells you not to worry because she will order a new copy to be put on the shelf.
Calling git checkout is a request to check out a specific version of the repository (or individual files) from a specific point in the repository's history.
If you ask the librarian "hello, I'd like to checkout this May 23rd issue of this magazine" then you can't act surprised that the librarian returns from the library's repository with the issue of the magazine released in May 23.
(speaking out of experience - I try to sweet talk my coworkers about git for more than 5 years)
The best I could stackoverflow for git was "git fetch; git whatchanged ..origin"
In Mercurial its even better (since it doesn't modify anything locally like git fetch does): hg incoming
Want to see what will be pushed? hg outgoing
When I use Mercurial I just don't think about it as much, it does what I expect it to do, which is something that is easy to take for granted.
https://git-scm.com/docs/git-checkout
Because git checkout does a whole lot of things, it takes lots and lots of text to describe what those things are.
hg help co | wc -l
$ 42
git help checkout | wc -l
$ 520I needed to do a complex merge in a script, rather than manually, which means I need to know how to do a) automatic merge strategies (conflicts will happen were it naive!) and b) how to choose different strategies on a per-file basis. By running `hg help merge`, it tells me that `hg help merge-tools` will help me for problem a) and `hg help resolve` will help me for problem b). Read those documents, and you find the list of internal automatic merge strategies, as well as the fact that `hg resolve` allows you to change the current resolution status of a single file, or re-run a merge tool on that file. It's not clear to me how to do this in git just from following its help pages, despite `git merge` being far more voluminous than Mercurial's equivalents.
Another example of a power feature is that anywhere you can specify a revision (or set thereof), Mercurial has a full expression syntax for computing revisions. The cases most people are used to are the hash (or any unique prefix thereof), the commit's integer id [1], tip (for the most recent), . (for the currently-checked-out revision), or the tag, branch, or bookmark (Mercurial's equivalent to a git branch) name. But you can specify quite complex revision sets as well: `hg glog -r "ancestors(draft()) and (draft() or branchpoint())"` will show you a log with ASCII graph (the `glog` command) of all the changesets that are not yet public, as well as specifically where they all branched off. The syntax is naturally inscrutable, but once again, `hg help revisions` (as pointed out by the documentation in `hg log`) will give you the full details.
Another surprisingly useful UX feature is that Mercurial is not afraid to alias the hell out of everything. `hg rename`, `hg move`, and `hg mv` all do exactly the same thing: record a file move. `hg glog` is short for `hg log --graph`. And any unambiguous prefix of a command is happily expanded to that command--useful if you don't remember if the document name is 'hg help revision' or 'hg help revisions', as they both work!
For repository features itself, there's a few things that really make things simpler for people:
* Mercurial lacks the staging area. This is a good thing.
* The UI generally aligns to the naming conventions of SVN, which makes it much easier for people transitioning from SVN.
* Mercurial treats commits as a much more permanent thing. There's no such thing as garbage collection in Mercurial, and you don't run the risk of losing commits just because you're not currently on a "branch" [2] like in git. Also, no scary message like "DETACHED HEAD STATE" if you decide to go poking at an older commit in Mercurial.
* Phases and changeset evolution make history rewriting much safer: you can't rewrite public history (determined by the phase), and changeset evolution means that pushing a rebase allows other people to safely develop on top of draft changes. It's made quite evident when you pull that your changesets are based on ones that have changed history, so you need to continue the rebase to stabilize your branch.
[1] All commits are assigned a unique, incrementing integer ID from 1 to N. These IDs are not stable: if you delete an integer, everything afterwards is shifted down. And if you clone a repository, it won't necessarily assign the same IDs. But they're still useful for referring to commits locally.
[2] Mercurial's branches are a completely different beast from git's branches: they are immutable properties of a changeset, and they are designed to be used for things such as release branches or version branches rather than feature branches. The Mercurial equivalent to a git branch is a bookmark. Hence why "branch" is quoted here--I'm referring to it in the git sense, not the Mercurial sense.
For the situations where you actually only want to partially commit things you can use "hg shelve", which is sort of like "git stash"
It's very nice to have when I've done a lot of work that most naturally should be split into more than one commit, or when I have temporary modifications (say, to config files) that I'd like to leave in place for now but not include as part of the commit.
Basically, it’s a scratchpad that’s gives me space to think and plan.
I used to use mercurial back in the day, before git took over the planet. Switching back to it would be slightly analogous to switching keyboard layouts at this point. Sure, qwerty is arbitrary and sort of stupid, but I've spent so much time using it that I've gotten used to where everything is.
In short, for similar scenarios I'd do `hg commit -i` to select a couple pieces I was sure I wanted in the commit, then `hg diff` to see remaining pieces or `hg diff -c .` to see my commit so far, then `hg amend -i` to select additional fragments or files. To undo some of that, I'd use `hg uncommit`. Same effect, fewer concepts -- your stage/index/cache is just materialized as a plain everyday commit that you can decide is done at any time.
I'm not going to argue that suddenly every vcs task becomes trivial with hg. Far from it. And these discussions often get bogged down when people argue from the standpoint "I only need X so everything else is unneeded complexity" or "you need all of this stuff because you might need to collaborate with multiple remote people editing the same files who need to back out some of your changes while they're working and have everything magically put back together at the end, oh and we need full control over what the final history looks like too." These VCS systems have to deal with a wide range of complexity, and reductive takes like "you really only need these 3 commands; why is it so hard??" don't illuminate anything. (Note that I'm not addressing this at your comment, which was not at all doing that.)
And, personally, I see no positive value in a staging area, given that you can achieve the same functionality via interactive commits or amending commits.
I have no idea whether tortoisehg remembers the state of what you've selected in its 'interactive commit' GUI, because I've only ever made those decisions when committing. Given I've been using it almost daily for about six years on a community project (i.e. not just linear commits by a single dev who doesn't need to care about anyone else), I think this is also evidence that a persistent staging area isn't super important.
It basically acts as a clipboard. Possibly hg interactive commits work in the same way, but then I do not know how that would be different from a staging area.
* http://stevelosh.com/blog/2010/08/a-git-users-guide-to-mercu...
Mercurial resisted rebase forever, and then they insisted that rebasing and editing history must be separate operations (why? opinions). And Mercurial doesn't have anything like an index, so no git add -e/-p, but instead you can do a combined equivalent of git add -p and git commit with hg record -- talk about "one command does one thing" nonsense.
Just let Mercurial die already.
Everything else you're talking about sounds like ancient history to me. `hg record` is now `hg commit -i`, so it's back to one command. `hg histedit` intersects with rebase, in that you can do some types of rebasing with it, but you tend to use them in different scenarios.
I don't tend to use them in different scenarios.
I routinely `git rebase -i origin/master`. Sometimes from detached-HEAD mode.
> `hg record` is now `hg commit -i`, so it's back to one command.
So Mercurial has an index? Or is that something else? Looks like roughly the same thing as `hg record -p`. An index is much easier to use. `git add -e` is simply amazing.
I've tried to use "bookmarks" in hg or whatever they were calling light-weight branches, but I've had trouble with it.
Git won.
I'm not saying Git is perfect. It's missing a few things, but it's better than all open source VCSes so far. And the work MSFT is doing is really helping too.
Which would both use `hg rebase`, so I'm not sure what you mean. Histedit is for reordering commits, or dropping some from the middle of a stack, and/or folding adjacent commits together. All in one go, if you so choose. All of which you could do with multiple rebase invocations, but histedit is an easier declarative interface to multiple rebase operations. On the flip side, it's limited to operating on linear chunks of the dag.
Something else. i for interactive.
> Looks like roughly the same thing as `hg record -p`
Do you mean git commit -p? (Or is it git add -p? I can't check right now, and I can't even predict which one git would pick.) Anyway, yes, it's exactly that.
> An index is much easier to use.
Why? I don't miss it in hg. I use it in git, but it mostly feels like it's an extra thing to remember. Yet most git users agree with you, so I'd like to understand why.
> `git add -e` is simply amazing.
I wonder what you'd think of `hg absorb`.
With `hg record`, if anything goes wrong, I have to start over. That can be extremely frustrating.
With `git add -e/-p` I can quit at any time and leave the things that were OK in the index while I take time to think about how to "absorb" the rest, or even commit what I have now and then go about dealing with the rest.
The index not only gives me the ability to do that sort of thing, but it also lets me get atomicity -- no matter what happens in the workspace, the index stays as I left it until I either add more to it or commit it or reset it.
For one, 'hg' is one of the easiest possible things to type at a command line... up there with 'ls'.
That difference, adding branches as a 3rd dimension, is why git is more powerful. It's also a reason why a staging area is important to be able to precisely decide what goes in each branch since they may be unrelated. That is not to say that hg's ux isn't easier to understand than git's. It is easier. In part because it's trying to do something else. That is also not to excuse git's unintuitiveness.
Not true in the least.
hg has the same dimensions that git has, just implemented differently. hg’s branching model is actually a superset of what git does.
A git branch is essentially the same as Mercurial's bookmarks. Mercurial also has named branches which are permanent and anonymous branching, which git doesn't have. You can read all about them at http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-me....
I guess you mean that hg commits do not have parent pointers and are thus not intrusively chained in trees, while an hg branch is a separate non-intrusive construct?
> That is not to say that hg's ux isn't easier to understand than git's. It is easier. In part because it's trying to do something else. That is also not to excuse git's unintuitiveness.
1. So... it is, albeit perhaps by sacrificing certain features.
2. I'm not convinced that git's admissibly more powerful branching model justifies the claim that hg's UX is no nicer and people who prefer it just don't understand git. If nothing else, what practical difference is there between creating a branch with no history vs creating a branch with history and then clearing it out? (That is: `hg branch newbranch && rm -r * && hg commit . -m 'new start'`) Both hg and git boil down to DAGs and have generally similar tools available to manage the grand set of commits.
Your commits are in the Draft phase, which means they can be changed at any time. By default (this is configurable) when you push to your team’s repo, those changes become Public, which means they won't change and it’s safe to code or rebase on top of them.
[1]: https://medium.com/@a_baez/mercurial-phases-introduction-4ee... [2]: https://www.mercurial-scm.org/doc/evolution/
Bookmarks are in base distribution for many years now and work basically like git branches. They did work well.
I've been using Mercurial nearly exclusively for interacting with git/github since, well, forever. The only case that breaks for me is git repos with submodules, which is the only reason I haven't been able to completely avoid git.
sounds like a great idea for a SaaS startup, who is with me?