>I will award honorary negative points for any client which dares to treat git rebase -i as if it were a fundamental primitive.
If you think that a git rebase is overcomplicated, rather than a fundamental primitive, then you missed an important part of the tool. And phrasing it this way is an insult to anyone who really tried to understand the tool - kind of like the nerd badge in schools.
Git rebase is fundamental to Git in many ways. It is also easy in many ways. At the minimum, it makes it easy to make mistakes while experimenting much less of a hassle, since the commit chain can be cleaned up later.
However, the point here is that git rebase is more similar to what the kernel developers and git developers intended to do with the tool, compared to the commit-merge workflow. There are two aspects here:
1. The tool developers want every commit to be feature-complete and that it won't cause broken builds at least in the master branch. This is impossible to achieve in the regular commit-merge workflow.You need to add the interactive rebases to achieve the goal.
2. Git hides something behind the snapshot model it claims to be based on. The commits themselves are snapshots. But the way changes are propagated between commits (like stashing, commit amending, merging, cherry-picking, rebasing, squashing, splitting, etc) depend on plain old text diffs/patches. It takes a while for beginners to realize this. The kernel devs were using emailed patches and tools like quilt patch manager for nearly a decade before they created git. You can still see the influence of diff, diff3, merge and quilt in the design of git. Knowing this makes you much better at predicting the outcome of these operations. Blaming the tool without trying these techniques is very uncharitable indeed.
I've been learning Pijul these days. All those complicated operations are condensed into a small set of commands in pijul. For one, it concentrates on patches only. I feel that part of Git's complexity is its mixing up of snapshot and patch model into a single program. Git didn't have the luxury of these diff alogrithms back then.
The easiest thing in the (git) world to understand is surely the cherry-pick.
Why on Earth do people make such a meal out of rebasing? It's just cherry-picking a bunch of stuff somewhere!
Honestly, try explaining rebasing and merging to someone unfamiliar with git - I think the concept of merging is (not hard but) way harder. Yet for some reason people who are .. well, who use git in their jobs decide rebasing is difficult and unnecessary. I don't get it.
And to 'rebasing as a concept is fine but the UI is annoying', really? I'm sure it could be better, but big deal? I use it multiple times a day and however 'could be better' it is, it's absolutely fine. If it was such a big deal, surely someone would have done it and it would be popular. Know your tools, or learn them!
Rebasing is a fundamental primitive, but not Git's implementation of interactive rebasing.
I very much subscribe to a "patch-stack" workflow, but have a great deal of difficulty doing advanced things in Git, because `git rebase`/`git rebase -i` do not support enough workflows.
Really the fundamentals of git are nodes (commits) and how they connect to each other. Everything else is abstractions on that.
Wonder if anyone has made a git client that lets you manipulate it at that level. Tree looking graph that allows you to drag connections to where you want them.
Is there any workflow in particular that you are missing in an Emacs/magit combo? I’ve found it easy to add a couple extra lines of lisp to fetch upstreams regularly or to “sync” worktrees in various remotes. The most complicated things I’ve encountered have been conflict resolutions, however, the tools did their best to help.
> The tool developers want every commit to be feature-complete and that it won't cause broken builds at least in the master branch. This is impossible to achieve in the regular commit-merge workflow.You need to add the interactive rebases to achieve the goal.
Why is this impossible to do with a commit-merge workflow? If I do work on a development branch, then merge it into the main branch, only the merge commit appears in the main branch, and that merge commit has the final feature-complete commit. The main branch then has an unbroken sequence of feature-complete commits.
The only two complications are (1) avoiding fast-forward merges with the --no-ff flag and (2) viewing the history using the --first-parent flag. The first ensures that you always have a merge commit, even in cases where the history could be accurately represented without it, and the second avoids display of the development commits.
I think the idea is that in a branch after a rebase, you have “main” with your new branch commits on top. This is exactly what it’d be like after merging to main, so you can test the branch with a high degree of confidence it’ll work correctly after merging.
Yes, but that only says that rebasing is no worse than merging with respect to testing the branch ahead of time. With respect to identifying when a bug was introduced, or the intended effect of a change, rebasing is worse because it cannot distinguish between a bug introduced during a feature implementation and a bug introduced during the rebase. The history that would be needed to distinguish between those cases has been thrown away.
I wonder if part of the issue isn't tooling defaults. In general, I always find grap > tree > linear [0], but not so with git commits. This might speak to my lack of proficiency with git, but I always find merge commits to be annoying, useless noise. Particularly on a codebase with lost of regular contributors (i.e. at work), there are occasions when I view the log, only to be greeted by a "Christmas tree" of a dozen commits that all say "Merged ${xyz} into develop". So even though rebasing loses some context through linearization, it at least doesn't add any noise commits to the log.
(Yes, there probably is some magic switch in git log that reduces the merge commit noise. But approximately nobody knows it, looking how the primary argument for squash+rebase workflow I've seen in teams I worked with was always "because it avoids the Christmas tree/chainsaw and overall denoises the log".)
--
[0] - For example this is a reason I vastly prefer HN and Reddit to phpBB-style boards. I find linear threads to be stupidly bad UX for discussing a topic. I know many people disagree, but I've been participating daily in enough forums of this style, some pretty high-volume ones, that I know what invariably happens is people recreating threading with quote-replies and lots and lots of pointless scrolling.
Sun used a rebase workflow on Solaris from 1992 onwards (well before Git came along), and the reason is that following non-linear (merge) history in a project that thousands contribute to just doesn't scale well for human minds. (Back then Sun used the awful Teamware.) For sure the tooling then was worse than now, but linear history is just very nice to work with because our brains are not that awesome.
Comment threads and code history are vastly different things. The latter in the end is always linearized and the merge turds (if present) encode bits of history on the side. The former really are tree-like, and also not about code but about natural language.
This can happen for either a rebase or a merge, though. In the case of a rebase, you’re left with commit(s) on top of main, which are entirely broken. In the case of a rebase, you have a working dev branch, a working main branch up to the merge, and a merge commit with broken code. The merge results in a much better state, because you have a working version to compare against. In addition, the history makes it clear that the merge caused the breakage, and that it wasn’t solely an issue with the new feature.
- Worries only about patches, not about snapshots too
- Only a few commands to learn. No complex switches
- Combines many git approaches in one. For example:
- pijul record (its commit) is an interactive code selection at the same time.
- Merges and rebases are all the same (due to the way commits are linked)
I'm one of the main authors. No stagnation, the future is bright but I've been founding a small company recently, not related to Pijul. I've shown an MVP to customers three months ago, now I'm close to 1.0 there. I promise I'll move back to Pijul soon.
Another issue is the Nest (our hosting service), I've been working on a new Nest that can benefit from being open source, unlike the current one.
Another indication that it's doing alright: I'll give a talk about it at BOB 2023 (bobkonf.de), and an invited talk in April at Collège de France.
First of all congratulations to shipping the first MVP! And I'm glad to hear that Pijul is very alive! No need to promise anything, I was just wondering.
I can't wait until Pijul escapes the nice and grows in popularity.
The author has a habit of taking his work offline for months. Hopefully, that's what's going on now. They are so close to 1.0 with their work. I seriously doubt that project stagnated entirely.
Git is many tools. For the purpose of this discussion it’s at least the following 2 tools:
1. A source code control system which allows you to manage the history and branches of your code.
2. A source code collaboration system that allows you to share code with others.
git rebase is excellent for (1). It could also be considered fundamental to it. I know I certainly use it a ton for this purpose and would find myself lost without it.
Unfortunately git rebase completely breaks (2) and if all git was is (2) it would certainly be considered an anti-feature, if not a bug.
I’m not sure I follow the logic? What is it about rebase that makes sharing difficult? Isn’t rebase just a merge strategy? And if you have code in a branch, and you share that, it doesn’t matter about the merge strategy? Or am I missing knowledge/misunderstanding something?
Rebase is a lot more than a merge strategy. Merging is only one of the things it can do. Rebase -i allows you to rewrite history, and if you rewrite history of shared code, it leads to all sorts of issues with git.
I’ve only ever used rebase in the very plain and not interactive mode of “please just apply my changes back on top of the incoming upstream changes” which does none of the history rewriting haha.
Another use of rebase is cherry-picking commits, which is also plagued with all sorts of issues. These aren't "bugs", since the issue is that commits aren't really suitable for doing this: patches (like in Pijul or Darcs) do solve this.
My biggest problem with git rebase -i is that it has to be interactive (without some serious scripting), and sometimes that isn't really necessary. For example, the rewording example in the blog. Having to go through a whole interactive rebase because I forgot to link to a bug number in one of the commits is rather annoying. It's also a little annoying that i can't do an autosquash without an interactive revase.
> My biggest problem with git rebase -i is that it has to be interactive
The way I see it, it's a feature rather than a problem. For once, the name (interactive) agrees with its purpose. Interactive rebases are meant to be manual editors for git history - sort of like how commits are meant to be manual operations. Automatic commits miss the purpose of all the flexibility built into the tool.
> Having to go through a whole interactive rebase because I forgot to link to a bug number in one of the commits is rather annoying. I don't get this. Rebases are cheap if you do it frequently. My rebases typically consists of maximum 2 ops at a time. It's not much more complicated that commits themselves.
> It's also a little annoying that i can't do an autosquash without an interactive revase.
I have never personally seen a use for autosquashes. Others may have the same experience and may be why there is no autosquash. However, it wouldn't be too hard to include if there is a good demand.
I'm not saying git rebase -i shouldn't be interactive. I'm saying that there are workflows that that don't necessarily need to be interactive, where git rebase -i is the only way to do it (ok, maybe you could build something with lower level plumbing commands, but you would have to duplicate quite a bit of logic that is in git rebase).
I contracted with one team that git rebased everything. It was awful and I hated it.
I think the fundamental issue is that - of all the things I want to be neat and well organized in a codebase, the commit history does not even rank. I just cant bring myself to care.
This seems to be one of the major divisions in SCM users, some see it as a clean up for seeing a understandable 'history', others see it as a falsification.
> some see it as a clean up for seeing a understandable 'history', others see it as a falsification.
I don't see it as a falsification. I see it as making the history less understandable. Having a track of what happened, can help in understanding what was intended. Code archeology regularly helps me understand Chesterton's fence.
Programmers are human. They make mistakes. The thing is not perfect at the time of squashing. When the inevitable issue crops up in production, I really want all the information I can get.
If you start cleaning stuff up, not only do you deny me information about how the code evolved, you also introduce another point at which a flawed understanding can mislead those that come after you.
The issue is most of my commits have little meaning and often include in progress commits where code is not even functional/tests may crash. Especially as I have tooling that builds artifacts for me based on commits/runs ci based on commits. Often I’ll commit something just to see the result from ci running it or to build artifact for a small test deployment fully expecting it to not work yet. After I’m done I’ll collapse all commits for a pr into one for the actual thing the pr aimed to do and aim to keep collapsed commit around <300 lines.
That is ok. A proficient code reader will see that you like to commit -m’typo’ and -m’testing CI has to go thru git; try this now’ and understand your life and save the detailed nitpicking for the overall diff, not each commit.
It is super nice to see if it was 20 code commits and then one test commit, or back and forth between tests and code, or a new test and then code commits.
The main problem is when the programmer who created the squashed commit is no longer around.
That subtle bug they introduced in that squashed commit now has to be picked apart without any context. If I have 10,000 tiny commits (and it's never quite that bad because programmers are lazy gits), I can reconstruct come of the context of how that bug got into the codebase and what was going through their head when it occurred.
The other problem with squashed commits is that nobody will ever agree on what the correct granularity of a squash should be. Even if you give me the ability to squash, I won't. Someone else will squash 1,000 lines of changes, and I'll want to scream.
And, to be fair, even Linux doesn't really like squashed commits at the individual level. Try feeding one of those big squashed patches into most maintainers. They'll tell you to GTFO until you bust that apart.
If I see some behaviour that changed in a commit that says "lint fixes", I can be pretty sure you didn't intend that. I'm still going to check, but if I don't find anything to give me pause, I'm confident in reversing it.
If I see it in a commit that says "fix edge case", I'm going to check, double check and triple check if that edge case is still resolved after my fix.
The "oops" and "work in progress" things hold no information, but since that's the default, well... Too bad.
A cute little paragraph is almost certainly going to leave out details I need. I'll probably ignore it, because it's either unnecessary verbiage, or inane. Probably both.
Again, humans are flawed. We have code that is probably broken. There's definitely a chance that the test is broken or incomplete too.
Also, I demand nothing, not even a certain commit message. What I ask is that you don't expend effort to destroy information.
I understand the desire to hide one's flaws. To hide the thought process to make yourself look better. But it's not necessary. Everybody has flaws and it's far better to have the thinking in the open, so we can see and work with it.
Quite the opposite, this is the best feature of Git. Commit often, don't be afraid to experiment since you can always roll back easily even if it's literally just a single comma - and then when it's time to share that code with others, then reorganize history into a sequence of well-named commits with clean description of what each of them does.
We don't expect people to give important speeches without writing a draft first, nor do we insist on seeing all their drafts. Why is this any different?
It's different for the same reason math teachers want you to "show your work" in addition to simply writing down the answer to a problem. They way you as a human have approached the problem and worked it out is valuable information in both the review of the work itself and in understanding what has gone wrong when something has gone wrong.
Think of your branch as being one long multi-day math problem. If I'm grading your work, I don't want you to show me all the parts you think are neat and tidy and important after you arrive at what you think is the answer. I want to see everything you tried, even the stuff that didn't work.
I'm not opposed to only having merge commits on master, but somewhere, on some branch which is recorded for all of time, I want to be able to see every decision that was made to bring HEAD to what it is right now, on the most granular level possible.
Yes, a maths teacher wants to see the working to a problem, but the working can still be the second draft, written neatly and well explained. For a complicated problem, it should not be expected that someone will read through all the “scratch work”.
> For a complicated problem, it should not be expected that someone will read through all the “scratch work”.
Do people really read through the changelog commit by commit? What's gained by that?
I don't read through it at all. I zoom into a point that I need to know more about. I have information (bug report, runtime behaviour on other data) that allows me to zoom into a specific part. The information I have is from the committer's future. It's highly unlikely that the details needed are in the summary that they wrote.
I maintain both branches - a WIP branch and a final rebased result. I agree with the age old concept that each commit on the master should be a full self-sufficient feature. I also like to keep the messy WIP for reference. How does the 'falsification' argument apply here?
I disagree. Every commit should be an atomic change that doesn't break the build including both compilation and it running properly. Doing what you are suggesting makes bisects near impossible, wastes extra time in code review, and wastes the time of people looking at the history because they have to comb through half baked ideas which they do not know if they actually work or were tested.
Falsifying history isn't wrong in itself. Falsifying a shared history is, because it breaks other copies of the repo. So long as a branch exists only in a single repo, then the history of that branch can be rewritten without issue. But a shared branch should never be rewritten, because you'd need to copy the alterations into all copies of the repo.
I take issue with tools that prioritize rebasing, because they usually make this distinction between rebasing a local branch and rebasing a shared branch. For example, GitHub's "Squash and Merge" or "Rebase and Merge" options break the shared history between the remote copy of the repo and my local copy. After such an operation, I cannot merge from main into my development branch, and must instead rebase my development branch onto main.
To be fair, once you're developing on a project with enough commits/day, you no longer have a real choice if you want an overall linear history. You will have to cherry-pick to main somehow.
Some people want to rather merge instead, but in my experience few people have the discipline to develop in large enough PR granularity to make the resulting merge commits meaningful and not polluting history while also keeping the non-merge commits meaningful by doing rebases while the change is still in review.
I would like a ui that can show me what conflicts are about to happen before I do a merge or rebase. Trying to resolve a conflict after it's already happened is much harder then if I knew what files and lines are about to blow up on me. Even better start warning me about which files I've been editing are going to conflict with origin once I eventually have to sync up
To be clear, I'd like to see the future conflict while my files remain in a clean state, so that I reconsider my own changes or work around the conflict before it happens
This is one of those cases where the solution seems difficult, but the difficulty is in the problem itself, not the solution. The source of the conflicts is the fact that you work with multiple people, in a distributed way on the same codebase. Those conflicts are going to arise one way or another. Git could tell them to you beforehand, but that would be just the same as rebasing and then aborting. The conflicts stay the same, no matter how you slice them.
In my experience best is to coordinate with other about code changes to avoid conflicts altogether or to fetch and rebase often to keep conflict scope to a minimum so they are more manageable. Also keeping commits focussed on single features/changes instead of spreading out the feature over multiple work in progress like commits so they can be applied as a standalone change helps. I really learned this when working in Gerrit Review for a while. Where there is no one pull request for a branch full of commits, but each commit is a change applied to master on its own and has to be reviewed/tested as such.
Git is not a magical tool that solves all collaborative coding problems, but more a toolset that helps you manages code changes. You definitely need to put some effort into the mental model of how to manage changes before you can use the toolkit to its full potential.
Tower offers an "Instant Conflict Detection" feature that should be right up your alley (I work at Tower, a Git client for Mac and Windows).
It will let you know in advance if conflicts will occur when merging another branch or revision (by merging, rebasing, or pulling). Here's an example: https://imgur.com/a/VCkqrBI
Yep, most tools are deficient in this area, as per the table.
My linked git-branchless tool will tell you before a merge conflict occurs, so that you don't have to abort it, although it could produce more information about the impending merge conflict.
> as if Git’s command-line interface were already the pinnacle of usability.
It is, for me. I love git and checking in my progress in small chunks that make sense to me is very easy with the command line tools. They're also easy to integrate and automated. Maybe they truly are the pinnacle of usability?
As another example, compare cashiers using one of those DOS GUIs with modern ones using touch screens. The simpler GUI works much faster, once mastered.
A very basic issue with git is that if you're editing a stack of commits, you can't go back to an earlier commit without completing the rebase -i and restarting it.
Not quite true. You can add `exec git branch progressN HEAD` every so often in the `git rebase -i` script, or you can `edit` commits and before `git rebase --continue` do `git branch progressN HEAD`, then later if you need to abort and restart your rebase you can rebase --onto one of those saved HEADs.
I think the hate comes from it not being very "noob friendly". It's designed for power users who are familiar with how git works.
In my experience, most git users don't really know how git works fundamentally. They just learn the commands for a particular workflow and stick to that. That's how I started. I've seen this to be especially true for developers coming from SVN or another centralized versioning system.
Whew this thread is rife with elitism. About git? To the folks sharing your difficulties with git, bravo.
To everyone who says they "don't get" how people could be confused or lost while using git, you are the reason why those folks are lost, and you're perpetuating the culture of elitism by playing dumb.
Git is hard as shit to understand unless you came from development before it existed, or you have had the luxury of trying other VCS professionally. Most people just know git, and it's confusing as hell if you have no reference.
Don't even get me started with how this has poisoned the industry on the whole: Proper VCS implementations with CI/CD are incredibly rare, even at places with world class engineering talent.
My hypothesis about git apologists is that they fall into one of 2 groups:
1. People who have an organizational development model and workflow which is equivalent in complexity to the Linux kernel development model and workflow (i.e. thousands of developers loosely coordinating the release of systems or mission-critical software on a regular cadence). For them git fits their needs better than almost anything else, and it makes sense because it was made for exactly that use case.
2. People who learned their first VCS after Github had reached critical mass and if you had to pick one VCS to start with, you picked git by default. For them their brain fits git, and they think "the git way" is synonymous with "the right way".
Many folks in group 2 never stop to realize that they are on a development team of 5 (or 50, or 500)...and they always cut their release from `master`...and all of their branches are always pushed/pulled from the same Gitlab remote...and within 5 minutes they can chat with anyone who's made a commit in the last 2 years.
I don't take issue with group 1 people who understand the git model and love it and adopt it in their workflow because they need its complexity and they're willing to pay the UX tax to get it. I take issue with the folks who don't understand the git model or realize they don't need any of the complexity and aren't aware of the existence of solutions like fossil and mercurial.
What I like about SourceTree is the ability to pick individual lines and „hunks“ to stage, as I often have changes and some debugging stuff sprinkled into some files (think printf).
Since it‘s not explicitly mentioned, I assume this is a pretty standard feature?
I wouldn’t mind switching away from SourceTree, it crashes often.
You can do this on the terminal with `git add -p` but yes it’s always slightly more intuitive with a proper editor (I mainly use the many-times-forked GitX for this)
The one built into vs2022 has this and works pretty well if you happen to use it already. I think vscode has many of these features but I haven't tried it there. Otherwise I'd say look at gitkraken (free for personal use I think) or sublime merge if you really want performance.
Personally I use sublime merge or command line for everything. The sublime merge/text interactions are really nice, being able to right click in a diff and have it open the file at the line. You can try them for free forever but the price may be a deterrent since the dark theme for merge is locked behind a license key.
I used `git gui` for that (not sure how "native" to git is it, though), and recently switched to `gitg` for both looking at tree and committing individual lines. Can't compare them with SourceTree, though, since haven't used that.
Also, when on command-line, I recently discovered `git add -i` for interactive mode (asks you about individual hunks and lets you "split" them), and `git add -e` (lets you edit the patch however you want).
1. git add -i or -p
2. History edits using interactive rebases
3. Using tools like lazygit or git-ui
4. Using stacked patch tools like stgit or topgit
4. Here is my favourites: Use magit on emacs or fugitive on vim
The last one on magit and fugitive feels like interactive addition is closer to editing 2 files.
I work at Tower and I recently put together a "Tower versus Sourcetree" comparison page (there are many features that Sourcetree is missing): https://www.git-tower.com/compare/sourcetree/
One feature I would’ve given a lot for when recently working with a large team on a big project:
Sometimes, it’s not obvious that a thing that’s made it to the main branch (whether committed or merged) is problematic until a while afterwards. In that case, later commits/merges may have been made that mean the problematic one cannot be cleanly reverted (conflicts, whether by accident or because it’s been deliberately built upon).
What I want to be able to do is to revert a commit _and any later commit that depends on it_ - or at least be able to see a graph that shows the dependencies to make a risk/reward trade off between reverting it all and trying to fix the problem manually.
This is definitely something it’s possible to do - I’ve done it by hand too many times!
You are describing "rebase -i". Just don’t pick the commit you want to revert and Git will replay the following ones one by one stopping when there is an issue.
> I just want a single command that will do all the reverts cleanly
Well, "rebase -i" will do that if it can be done but that’s unlikely unless your commits have nothing in common.
As changes will be necessary to adapt the code to the removal, it’s kind of hard to tell from the start what will be affected. Things might have knock on effects. It’s funny because I don’t really like Git but this is one of the case where what it does seem to be the best doable considering the actual complexity of the issue.
If you just want to see what will be reverted you can do a three way diff between HEAD, the commit to revert and the commit you intend to revert to btw.
I think you’re maybe not getting what I want - unless I’m misunderstanding, the three way diff you suggest won’t work for this.
In the simplest possible configuration that exhibits the pattern, there are commits like this … - A - B - C. To revert A cleanly, C must first be reverted because it changes code also changed in A. B touches a different part of the code and so doesn’t need to be reverted.
Factor in a few days worth of commits from a large team, and it’s easy to see how very complex trees (even graphs, I think, so long as all the dependencies point backwards) can appear. But it _is_ always possible to get a minimal ordered chain of clean reverts that are required to revert A and all its dependencies.
It’s definitely true that, as you say, things might have knock-on effects - like, perhaps there no textual dependency from B to A, but the logic is very much dependent. Thorough testing of the results is needed. But in a large well-factored project the chances of things being fine when an entire dependency chain is reverted are (in my experience doing things like this) surprisingly high.
> I think you’re maybe not getting what I want - unless I’m misunderstanding, the three way diff you suggest won’t work for this.
To revert A you want to compare the difference between C and Z (commit before A) to the difference between A and Z so as to see where things which were changed in A will impact what’s in C while reverting so you can see what’s salvageable and what’s not.
To come back to your chain of commits, use "rebase -i", do not pick A, and "rebase —skip" every following conflicts and you will end up in the state you want.
Even in principle you will need 2 commit hashes to make this work, showing an editor with n lines and moving a single line up is imo easier than copy-pasting two long hashes.
If someone has a clean commit that is a district unit of functionally and passes all tests, why would that not have simply been committed as an independent change prior to continuing work? The only way a consistent unit of code would exist to revert is by stacking it on such a change.
I am not sure I have ever encountered a situation where targeting a single commit to revert would have actually worked(from a rebased merge). I would go as far as saying that git revert should be a nuclear option reserved for only the worst of situations(urgent PE hotfix?). If something is worth reverting and was missed by the engineer and the reviewers, it seems the like fix should also atomically contain the explaination with a test to prove the issue was fixed. Because of this mentality, I believe it has been several years since I have seen a 'revert' in the wild.
Maybe I am alone in the industry with my opinion. However, I have seen the same patterns unfold on many teams. ...A lot of concerns with switching to a dead simple git workflow that fade almost immediately after trying it.
Just my experience (backend batch jobs, applications, and rest services).
If someone has a clean commit that is a district unit of functionally and passes all tests, why would that not have simply been committed as an independent change prior to continuing work?
This is exactly the kind of change I’m talking about - the problem is it’s later discovered to have flaws that the tests did not reveal, but enough time has passed that later changes depend on it.
I am not sure I have ever encountered a situation where targeting a single commit to revert would have actually worked(from a rebased merge).
It almost always worked in my experience. The systems we’ve worked on must be architected differently.
If something is worth reverting and was missed by the engineer and the reviewers, it seems the like fix should also atomically contain the explaination with a test to prove the issue was fixed.
Agreed - the problem comes if the fix is not obvious and a fix cannot immediately be applied. In our workflow, when we have belatedly learned of a problem a change is causing, a revert should then be done to keep the integrity of the main branch.
I should stress that this is an exceptional case - but we did see it a few times a year.
Thanks for doing the research, there's so many git GUIs it saved me a lot of time. Limitations of these GUIs leave you in a limbo switching between them and the CLI.
The "git sucks" heading might turn off readers; there are so many "git sucks" articles with less nuance and research than this one. (Notice most of the comments already are just related to that, or git in general.)
> The "git sucks" heading might turn off readers that have otherwise have been interested
Thanks for the feedback. Do you have a better idea for the heading name?
> Notice most of the comments already are just related to that, or git in general.
After having read the comments for many Git-related articles, and having posted a few of my own, I can tell you that this would have happened regardless of how well the article was written :)
I don't think it would have been as bad without the provocative title and subheds. They effectively hide the work you've done and provide handy hooks on which commenters will eagerly hang their generic tangents.
This is a pretty lousy aspect of HN and I don't think it's any kind of indication the article is somehow not well written. But I think you underestimate how much these initial conditions affect the quality of discussion.
absorb: when you’ve got one commit eg adding a new method, and another commit making use of that method, and you then tweak both bits of code, “absorb” automatically merges your add-method tweaks into the add-method commit and the use-method tweaks into the use-method commit
The CLI interface of git is very good at enforcing you to be aware of the underlying model (local state and the repo’s history). This allows for the user to draw an accurate user-model in his understanding of the system.
Adding an “undo” command would be convenient, but it would hide the underlying potential away. This is something that should belong to a GUI client, and I still would want to know what is it actually doing.
Instead of hiding the abstractions behind a “friendlier” CLI, Git shows you its real power and that of VCSs in general, by having a lower-level API.
Not even the multiple GUIs built on top of Git, adventure themselves into hiding or dumbing down the abstractions that allow you to do quite complex things with the code and its history.
> Instead of hiding the abstractions behind a “friendlier” CLI, Git shows you its real power and that of VCSs in general, by having a lower-level API.
But that’s simply not true. Git is just inconsistent in how it does things.
Sometimes it wants you to deal with its inner state (typically the undo where you just need to move HEAD to a previous commit which might be only visible in the reflog). Sometimes it introduces complex concepts which would be simpler if they were just exposed for what they are (stashes are just temporary commits).
Honestly Git is a mess. It works but the UX has always been awful.
> The CLI interface of git is very good at enforcing you to be aware of the underlying model (local state and the repo’s history).
Awareness of state is sometimes important, sometimes you just need awareness of operations. And awareness of git's data structure does not necessarily map 1:1 with understanding the state of the code base. Not saying you’re wrong, just saying that this may or may not be a good thing. I’m personally leaning towards this could be improved.
Really good advanced tools should work well for common use cases, so you can master it incrementally. Git is extremely frictionous for certain simple tasks, which is evident if you look at stack overflow. If a user wants to do something very simple in human terms (like fix a typo), and you get a lecture about merkle trees and reflogs, then I think there is room for improvement.
The truly important question though, is whether the UI can be improved enough without changing the data model (ie can replace the UI without replacing your repos).
I only properly understood rebasing when I started using Ungit [1], visually seeing commits being replayed on the base branch makes it much more intuitive.
Another was treating branches as "labels", that can be advanced to a more recent linear commit timeline. Very useful for a production branch following the main dev branch (essentially electing commits as production-ready).
We are working on "the next git" that brings version control to the rest of the world.
> No one bothers to consider: what are the workflows that people actually want to do? What are the features that would make those workflows easier?
What a coincidence, I just created a document [0] that collects engineering and UX issues that we are running into with inlang (localization infrastructure built on git) [1]. Part of bringing version control to people outside of software engineering is fixing UX related issues.
For example, your proposed `sync` command is interesting. Our observations lean towards some real-time collaboration workflow that could make `pull, push, sync` workflows redundant. Applications that benefit from version control like a next-gen Figma, Adobe Premiere, Excel, etc. require real-time collaboration. A question that I've been asking myself whether real-time collaboration in software engineering makes sense too. To be elaborated! :)
Some of the commenters here get hung up on whether git needs undo when nearly all git operations are undo-able. That's just one aspect of the problem:
- It is evidently difficult for git GUI front ends to implement truly general purpose undo/redo the way any users expect any other GUI to have. This makes discoverability hard, maybe impossible, with a GUI front end to git.
- Not all git operations map to the "generic operations on a selection" model most GUI software implements. There is no general "do this to that."
- You can create a visualization of a git repo, but that visualization doesn't do a lot for a GUI, because of the lack of a selection or focus.
It all still has to be coordinated in the user's brain, which is why most people end up just having to develop a deep understanding of the git command line. GUIs do not take away much, if any, cognitive load. Imagine having to know how a text editor manipulates the structures representing a document.
It's hard to think of another design domain that is so intractable for GUI interfaces.
I get where the author is coming from, but personally I feel like the juice isn't worth the squeeze. The thing about git is that it is incredibly powerful, and the model is very simple and well thought out. The only problem is the CLI is full of warts. That sucks for beginners, but once you get over the hump, git is like a chef's knife—you can do anything with it, quickly and efficiently. So any layers you build on it will, at best, make it easier to learn, but they won't make it more powerful. On the downside, making a legible UI will require some opinionated decisions about what to emphasize and what to de-emphasize (sort of like how Mercurial is designed in a way that discourages rebasing).
As to the specific suggestions, some of them are very poorly thought out. For instance, the proposal for `git reword` suggests you shouldn't need to have the commit checked out since it won't create a merge conflict. Sure, but the SHA will change, and this will change all downstream commits, which means you could potentially be triggering a massive, silent rebase that will blow up spectacularly when you try to push.
Another one is the `git preview`, saying you should be able to predict the conflicts on a rebase. But this is exactly what rebase does already! You start rebasing, then you get a conflict, at that point you can either fix it and proceed or abort the rebase being no worse for wear. Obviously you can't see the subsequent conflicts until you resolve the first, so there's no magic "see all downstream conflicts for the entire operation" possible (if that's what the OA meant, I'm not sure).
Finally, the `git undo` is just a hand-wavy ask for the functionality provided by `git reset`. Combined with `git reflog` you can undo arbitrary operations including ones that you had abandoned and "overwritten". It's an incredibly simple and powerful model. I get that the `git reset` flags are not super intuitive, but they are few, terse, and domain complete.
>That sucks for beginners, but once you get over the hump, git is like a chef's knife
When do you get over the hump? I've been using git for nearly a decade, I understand the internals of its data structures, I can talk about the difference between a rebase and a merge, and I still need to reference a cheat sheet for anything more complex than creating a branch, pulling from head, and committing.
What really helped me was to create aliases and short scripts for the variety of commands that I used. For example, I created a small script called `git-back` that is `git reset --soft HEAD^1`. The `git-back` takes a parameter for how many commits back you want to go.
Not sure if this is what everyone wants, but adding a wrapper language around the commands was really powerful for me. Everything could be tab completed, used names and terms that I could remember, and at times the new commands became so baked into my mind I forget at times they are not part of core git.
On the contrary: I myself have implemented these better operations, and they work great. They also exist in some other VCSes, such as Mercurial and Jujutsu. You can see the `git-branchless` column in the table for comparison with the other clients.
Apologies, but I misunderstood what you meant by the "downstream" conflict situation. That's not possible in git-branchless, but it is possible in Jujutsu, since it stores conflicts as first-class objects, so it can actually proceed with the application of subsequent patches even if a previous patch conflicted.
`git rebase` can be started and aborted, but to start it safely, you have to first set aside all of your existing work in the working copy. You can't really run it on the background or in parallel, which makes it annoying to do operations like rebase all branches, and can ruin build caches, which ends up being a significant problem on larger repositories. It's possible for the UI to show an icon next to each of my branches indicating whether they would rebase onto the main branch successfully, but no interfaces at present do (including my own). Or, for example, I should be able to start dragging a branch to indicate a rebase, and the UI should speculatively check which target branches can be rebased onto successfully and indicate that.
Would love a git/PR workflow that was aware that I work on the next feature (or two) while the previous PR is being deliberated. I need a pipeline system where I decouple “do code” and “negotiate merge upstream”. Managing this manually is a pain, especially over multiple connected repos.
In my opinion, you should certainly go for 1.0, unless you are planning some breaking changes at this point - which I guess you are not, after reaching beta. My general deduction is that tools with a few bugs at an early 1.0 has a better chance of succeeding than tools that stay too long in beta. It's important to ensure that interest from users, distro packagers and commercial adopters are kept alive while waiting on 1.0. I'm still waiting for pijul to be in the distro repos, though the crates version work satisfactorily. This may turn away many other potential users. Alphas and betas should be time-limited, not bugs-limited. Bugs are what patch versions in semantic versioning are for. Remember: 1.0 is a magic number - it increases the exposure of your tool and potential contributors by a large factor. By your standards, git would have stayed in pre-1.0 for a decade and would not have become this popular.
On a personal level, I use pijul for managing my dotfiles. I haven't encountered any bugs yet. The only feature I miss from git is the availability of tools like syntax highlighters for diff and record and UIs like tig, gitui and magit. But again, those are just features you could add as minor versions. That aside, pijul feels like magic. A handful of pijul commands cover most of the use-cases of git. After using git for so long, I always wonder if I'm using pijul the wrong way, even though I get the expected result. I'm only familiar with svn, git, bzr and hg. Perhaps Darcs would have given a better idea about what pijul really is.
I was thinking of doing a synchronous release of 1.0 along with the new Nest: the current one has a cool architecture (replicated over 3 datacenters, using Pijul repos as CRDTs), but doesn't scale well, I'm working on a serverless version. The hard bit is convincing Pijul that it's talking two a real Pijul repo, whereas it's actually talking to a serverless cloud (that's already solved btw).
EDIT: I also don't think there's a "right" way to use Pijul. The magic of algebra means that you can't possibly break the associativity and commutativity properties of Pijul patches, so you can do whatever you want, I'm sure it's fine.
Thank you for the reply! I'm eagerly awaiting the 1.0 release. Good luck to you regarding the new nest and well as the new venture!
> I also don't think there's a "right" way to use Pijul. The magic of algebra means that you can't possibly break the associativity and commutativity properties of Pijul patches, so you can do whatever you want, I'm sure it's fine.
There is a certain time to 'internalize' the concepts of a tool like git or pijul. It took me years with Git and I'm only starting to be confident about my git skills recently. I haven't had that much time with pijul and I haven't absorbed its concepts yet. Despite that, pijul feels like a concept that I can learn much faster. That causes this 'sunken cost' fear. If it was so easy to learn a VC tool, why did I take so much time with Git? That's what I meant with that comment.
I'm a big fan of pijul. I even have a plan in a future project to manage editing history using pijul concepts (or library).
> The Git version control system has been causing us misery for 15+ years
I think git is pretty good. It was good enough to be the first VCS to really reach critical mass (before, I used RCS, CVS, SVN, and hg). It might not be the BEST vcs, but it's got everything I need and it's easy enough that I can teach non-technical people to use it and clean up after them when they find the footguns. And the cli has been shortly but surely improving. It has facilitated my collaborations for 15 years with very little misery.
I often use Sublime Merge to reword commits (edit commit message, even other branches, the entire log is visible), or to split up commits (it undoes the commit and you get everything in the working directory), so I’m not sure if his comparison table is entirely correct. (At least from a user point of view I can easily edit or reword).
One other nice feature of Sublime Merge is the squashing of two commits, ignoring the latters message (as a fixup). Not sure how to do that in one click or command with cli git…
Can you reword/split commits without having them checked out, or without touching the working directory? That’s what these criteria are about, and from your description, it doesn’t sound like you can do those directly in Sublime Merge.
You can only edit any commit that's reachable from the current HEAD without checking it out. I.e. a commit that's in a branch that's not merged back into wherever you currently are can't be edited.
(I made a test repo to check this, because it had actually never come up before in my day-to-day usage.)
Thanks for pointing this out. I confirmed that you can reword a commit without checking it out, with the caveats:
- It has to be an ancestor of `HEAD`, like you said.
- Doing so doesn't invoke Git's `post-rewrite` hook, which can cause interoperability issues with other tools :(
- Doing so will abandon at least some descendant branches (possibly all descendant branches which aren't checked out, or possibly just those which branch aren't ancestors of `HEAD`).
- Doing so doesn't seem to be undoable inside Sublime Merge via the undo command.
Rewording “too easily” would inevitably lead to someone accidentally rewording a commit on a shared branch (such as main/master).
What I want in a git gui is first and foremost the fundamentals of my workflow built into the tool.
What patterns for branch names means they are private? Or short lived? Or forked but never merged back? This should control e.g how a graph is drawn (you don’t bend the main branch etc) or how branch pruning is done.
If I push a feature branch, later it’s merged on a server using a as squash commit and deleted remotely, then there is no way to say it should be deleted locally because there is no merge commit. This means something is missing. Either the knowledge of deleted branches should be communicated. Or the record that the branch was pushed to the central repo but is since deleted there must be saved. And this requires also specifying clearly that a remote is the source of truth. Git just doesn’t care. The remote list is basically a map of names to urls. No name is more special than another, just like no branch names are really special. And while flexible, it’s also extremely limiting.
> The Git version control system has been causing us misery for 15+ years.
Not having git and using most other VCS (fossil and mercury are pretty good, too) creates way more misery.
> No one bothers to consider: what are the workflows that people actually want to do?
Well, here is where the problem is. Git has some fantastic workflow features that most people don't learn or use (https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). Workflow is also problematic because it is exactly where people will demand a wheel, except for more round, every time.
So... how could it be better? Abstract it away to the os and filesystem so it is just part of the routine. Having full support for versioning everywhere would help because many of the rough edges with git are caused by having to support multiple OSes. A lot of confusion is that you have to use git's own tools or do an add/commit cycle for what should just be os file commands. These issues exist because git is not an OS level tool. Imagine commands like find or grep can return the file and version... imagine being able to just mv \dir;crusty-branch \new-dir and it just works. Back in the day, VMS did primitive versioning and it was quite nice (ie \dir\myfile.txt;22 where 22 was the version). Adding versioning like this also would encourage vendors to have sane file formats, so they could be versioned by the OS and pick up almost free change history features.
Slapping a UI on git isn't all that helpful - many, many users just use git from the ide or command line, anyway. As far as workflow goes, the author has a point that git does not come with a lot of strong opinions or obvious ways to do things out of the box.
You’d think that Microsoft and Github would have a monopoly on this given their personal contributions to Git, ownership of Visual Studio Code, and ownership of the largest Git hosting PaaS.
Don’t get me wrong, VS Code and Github are both okay. I use them both and drop into the integrated terminal for situations where my muscle memory is faster or the workflow is going to be more complex. I also find that setting VS Code to my default editor for Git makes this pretty seamless. Anyway, I find it interesting that there doesn’t seem to be a big focus on the sort of features the author mentioned in VS Code.
Now that I think of it, this is also one of those few circumstances where I don’t need or want the tool to be modular. VCS are such a fixture today that I just expect this to be built into the IDE’s GUI. A separate app, even with perfect workflows, may be just as much of a bother as a terminal. After all, what’s stopping me from writing a handful of clever aliases?
The only passable git GUI IMO is the one built into Jetbrains IDEs. VSCode makes only the very most basic workflows simpler (doing a commit) so I use that as well on the rare occasion I'm using VSCode. For every other git GUI, I'd rather just stick to CLI.
I highly recommend using Tower. Yes, it’s a paid app with a yearly subscription fee, but it’s worth it. I really enjoy using the rebase functionality to reword, split, and reorder commits.
I also know how to do this on the command line, but sometimes I enjoy using a gui on macOS.
Can you specify which of the features in the table from the article it provides? If so, I can update the article. The last time I used Tower, I was not impressed, for the same reasons as the other Git UI tools in the table which try to offer simar features.
I would say that while Tower can't achieve the specific features to the specifications defined in the article (as I understand them), its main advantage is how stable, predictable, and at-home it feels on macOS, which cannot be said of /any/ of the other GUI clients (where applicable, on macOS). It's responsive, commands finish as expected, and I can also perform many operations with a drag and drop or via the context menu. This predictability lends a lot of confidence to me achieving my work, and I feel others feel the same.
As for the features, it:
- supports `undo` of arbitrary operations quite well.
- has a dedicated `reword` (as "edit commit message") command/flow (but will ask if you want to stash your current working copy, with the option to automatically re-apply the stash)
- `split` kind of works by entering a "edit a commit" flow, which lets you stage and commit multiple times. In short, editing a single commit can generate one or more commits.
- `large-ops` and `large-load`: I've never noticed the GUI becoming unresponsive, but it's possible none of the repos I've checked out are large enough.
Note: Tower on Windows feels out place on Windows/ doesn't work as well as on Mac, but is still a formidable git GUI.
Thank you for mentioning Tower! I would just like to add that Tower 9 also included many improvements around the merge/rebase experience, including an Instant Conflict Detection that should satisfy the "preview" workflow mentioned.
Sapling has basically combined Mercurial’s UI/UX, and added several more nice features on top, and added Git as a backend (ie, you can use sapling to seamlessly contribute to git projects) - https://sapling-scm.com/
Amen. When I finally had to switch to git, workflow with VCS became misery, exactly as the author suggests. It's mostly googling to Stackoverflow answers for simple operations, and being unable to memorize all those ten CLI options that you must type. Sadly, Mercurial has been dropped from Bitbucket in recent years.
Someone should build a chatgpt type of tool that resolves merge commits. It should be able to read commit messages, and both parent trees, and just merge both cleanly. Train it on github. Just credit me on your website ;)
I don't really understand how SmartGit failed you? In your table of results it covers at least as many features as the others.
I call this out because I have been using SmartGit as my only git gui now for about 10 years and I think it does a grand job. It doesn't hide any information about the repo and makes just about any operation pretty straightforward. I also find it's built in diff and merge tools better than others. It also performs well enough and had been super stable.
(I am not affiliated with SmartGit, just a happy customer).
Ok I will end up agreeing with you, for the specific clauses where you require the operation be possible on any commit, even if its not part of the tree of HEAD.
I guess I reacted strongly to the negative review because despite your assessment it is still an eminently usable tool and in all the time I've used it haven't needed it to do anything more than it does.
As per my original comment though, I'd you haven't tried it's conflict resolution/merge tool I would recommend you do and perhaps you might be tempted to give it at least half a bonus point :)
If I recall correctly, the last time I tried it, it was unusably unresponsive on large repositories (500k+ commits), so I'm unable to use it for work :(
Re-reading the article and I see that your table headers are misaligned. I see you did mark SmartGit negatively in every category. It does support many of those features, so what gives?
SmartGit have not received credit it deservers, sure there are hi quirks like showing unstaged file tree, but workflow with git made me switch to it from GitKraken, GitExtensiona and others.
I would call the benchmark article rather subjective due to limited amount of comparable features and excluding most frequent workflow components with a respective ease of use score.
many say that git has an intuitive/concise data model. But it seems that even git team itself has not quite got it.
Looking at one of the latest changes [1] in which a _new_ merge strategy (ort) was introduced and made default one can ask how is it possible that so fundamental change happened 15 years after git was created?
Maybe the model is not so simple as it wants to seem.
Does anyone have a set of shell aliases for more common Git workflows? It would at least smooth out some of the idiosyncrasies and memorization (need to Google search) associated with the CLI.
Ah, I should have been more precise. If you were to reword a commit in the equivalent manner as `git rebase -i`, which is to say, reapplying any descendant commits/patches, you would be guaranteed not to get conflicts while applying descendant commits.
I suppose there is some possibility for merge conflicts in a workflow where you reword a public commit, which changes the merge-base in an unfortunate way and causes conflicts to appear which wouldn't have otherwise. Primarily I meant the workflow where you reword local commits only.
More enlightened version control systems like Mercurial can handle this better, such as via its "commit evolution" feature. If you then rebase on top of a reworded commit, the patches will apply the same, and you can resolve the so-called "divergence" by running `hg evolve`. (It's still possible to have un-automatically-remediable divergences, such as if two people reword the same public commit in different ways, but it handles the common case.)
I have used IntelliJ's Git UI and never noticed it having those features as described in the article (such as reword without checking out or merge conflict previews). Can you show me where to find those features?
If I'm reading this correctly, you cannot reword a commit without first checking it out, and you cannot preview merge conflicts without first starting a merge/rebase operation? Those are the criteria as described at https://blog.waleedkhan.name/git-ui-features/#rubric
Reword: you don't need to check out the commit. The 'log' tab shows a tree of the commits to the repo. This log can be filtered in multiple ways: for example by branch or via a search string. You may right click a commit to reword.
Thanks. I confirmed that you can reword a commit which is reachable from `HEAD`, but not those on other branches in this way, similar to Sublime Merge elsewhere in the comments.
I right-clicked commits not reachable from `HEAD` and the Edit Commit Message option was disabled, so I'm assuming it can only reword commits reachable from `HEAD`.
Thanks for posting this interesting article. I work at Tower (Git client for Mac and Windows) so I feel compelled to chime in! :)
Becoming more productive with Git is one of our main goals, and I'm happy to state that most of the operations you address are already included in Tower (apart from "sync", which we will think about internally).
As for the others you mentioned:
reword - you can edit any commit message from the currently checked out branch by right-clicking the intended commit and selecting "Edit Commit Message"
split - you can edit any commit from the currently checked out branch by right-clicking the intended commit and selecting "Edit Commit". You will then be able to reform that revision into one or more new commits.
preview - Tower offers an "Instant Conflict Detection" feature that will let you know in advance if conflicts will occur when merging another branch or revision (by merging, rebasing, or pulling). Our latest major update was focused heavily on creating a better merge experience and you can also see the number of unresolved conflicts that you still need to resolve (with a progress bar being shown in case of a rebase). If you mess things up, you can also undo the latest operation or abort the Merge/Rebase operation altogether.
undo - you can undo pretty much any operation with CMD+Z (or CTRL+Z on Windows). This includes not only commits, branch creation/deletion but also more complex operations like merges, rebases, and even file discards (which is not something Git actually supports).
large-load - Tower works well with large repos. We do build caches on first run, so the initial run might indeed take longer to display very large sets of data (e.g. 10k+ tags).
large-ops - We designed Tower from the ground up to remain responsive when doing any kind of operation. All commands run asynchronously, so you can e.g. push a branch and immediately checkout another branch simultaneously.
I hope you give Tower a try in the near future — feel free to get in touch with us if some other question pops up.
The Git version control system has been causing us misery for 15+ years.
I think this is uncharitable at best. It was a huge step forward compared to then popular VCSs such as Subversion, I have loved working with Git since it was created and I still enjoy working with it every day.
Mercurial has been around for approximately the same length of time, and from a UX perspective, I find it to be much superior to Git, which was largely built in terms of "what is the easiest way to solve this problem from an implementation perspective", rather from the user's standpoint.
Of course, Git won for a reason, but I doubt that it wouldn't have still won had it incorporated some UX design ideas from Mercurial or elsewhere.
> I have loved working with Git since it was created and I still enjoy working with it every day.
I have been profoundly frustrated by working with Git every day, hence the article, and the linked set of tools which I wrote to improve my workflow. Not even because its mental model is hard to grasp or that the UI is poor, but because it doesn't even streamline the kinds of workflows that it should be good at (in the article, and discussed in its own `gitworkflows` man page).
To be fair, there are some real differences; e.g. there is no easy "hg rebase" by design, and whether that's a good or bad thing has been a topic of contention for about 15 years. But that Linus wrote it gave it a huge boost, and GitHub really was much better than many things that came before it (and arguably, still is).
Having the kernel as an anchor customer definitely helped, but there's also the reason that Linus wrote git in the first place, and that's that every other competitor was horrendously slow by comparison.
git, mercurial, and bazaar were all released at pretty much the same time (within weeks of each other in March/April 2005). AFAIK all in response to the whole Bitkeeper situation at the time.
I don't think performance was the main motivator; from what I recall it was mostly that Linus felt that the subversion model was "completely broken" and that there weren't any good distributed "bitkeeper-like" tools out there (and then, suddenly, there were three).
Linus was looking at monotone as an alternative to BitKeeper, but in his words "performance was so horrendously bad that [he] tried it for a day and realized [he] cannot use it": https://youtu.be/4XpnKHJAok8?t=711
It was very noticeably slower on all but the smallest projects. I started with it but switched to Git later for some open source work and that was one of the first impressions I had.
According to Facebook Mercurial was faster for them, but that was in 2014 and they had to put work in to actually make it fast. Their use case is rather outside the mainstream of course.
"When we first started working on Mercurial, we found that it was slower than Git in several notable areas. To narrow this performance gap, we’ve contributed over 500 patches to Mercurial over the last year and a half."
Personally I can't recall any serious performance difference after I switched from mercurial (which included some large-ish repos) to git, but it's been quite a few years ago and perhaps I just forgot.
Git is very much "here are tools, do what they want with them". There are no safety scissors included and the user must understand the problem to solve it. And the tools themselves are getting better over time, but you still need to understand what exactly you're doing, there is not much DWIM there and not that many shortcuts and no undo button.
Like the one I use semi often (aliased to re) is "git reset HEAD~1". If you read the Git book, you know what reset does, you know that HEAD is where you currently are, and you know that "~1" means "commit before". So you tell git to reset current tree to commit before the one you're currently on (essentially "undo commit").
Actually, having "git undo" to "revert whatever I just done, regardless of what it was" and "--explain" ("tell me what I am about to do") would probably help a lot...
1. Git was faster than mercurial and bazar, eventually mercurial became fast but at that point it was too late
2. Git had a better svn backend, you could try git and get benefits from it even if your company used svn
3. Git did a lot of things that other dvcs didn't do (rebases, partial commits, history edits, local branches)
A lot of the UI simplicity of other tools rests on not doing (3). For example, OP awards negative points for rebase but as far as I am concerned I won't even consider using a UI that doesn't support rebase.
> Mercurial has been around for approximately the same length of time, and from a UX perspective, I find it to be much superior to Git
I started using Mercurial as the first serious DVCS I used (dabbling earlier with things like bzr) and my experience doesn’t support this at all.
I think it’s hard to underestimate the degree to which familiarity skews these assessments, especially with the additional confounding factors of project custom and experience. If you first used Git when contributing to a larger or more complex project than you were used to, it’s easy to misattribute the challenges to the tool and forget that everything got easier with experience using any DVCS.
This is especially true for the not uncommon case where the problem is really that someone has strong opinions about how they think the tool should work and refuses to learn its actual design - I’ve known multiple people who ranted about Git who were also the guys who hacked up their development boxes before saying a project was too hard to install (“Python packaging is terrible!” “Didn’t you use sudo to overwrite /usr/bin/python with Python 3 right before getting all of those Unicode decode errors?”), or, in one notable case, say Debian packaging was broken after they manually upgrade MySQL and somehow managed to render the system unbootable.
It's true that it's easy to forget one's early challenges, but we have empirical support that design decisions such as the staging area are objectively difficult for beginners to adopt. See https://investigating-archiving-git.gitlab.io/. Mercurial, of course, doesn't have a staging area.
Sure, but the staging area isn’t something you need to understand deeply to use Git since most common tools abstract it. Given how much more frequently the researchers’ subjects mentioned it, the big win would appear to be avoiding merge conflicts and better tools for reconciling them.
Simplicity of implementation prioritised over simplicity of interface can take you a lot further than the other way around, in a fast-changing, experimenting environment.
I have found this to be a common assertion, but my experience has been different.
Mercurial Queues exists and people use(d) it. It has many, many more footguns than Git, and it's shockingly easy to loose work. The fact that this was ever acceptable is interesting.
Phabricator is not good, or at least not as good GitLab, GitHub, or Gerrit (IMO). This is important, because Git alone is half the picture nowadays.
The extensibility of Mercurial is also interesting, and leads to codebase-specific commands. This is maybe good for long-term developers, but makes onboarding new hires just that much harder.
So Mercurial's UX being that much better than Git is - in my very limited experience - a myth.
I must be weird one. I clicked with Git immediately but didn't gel with SVN/CVS at all.
I do have a bunch of aliases and one added command (shortcut to deleting some stuff) but nothing really more complex that shortening up commonly used stuff.
It’s Stockholm syndrome mixed with you being an expert at a specific tool.
The reality is, Git is unintuitive, and makes nearly every common thing the average person wants to do a complete pain in the ass. I understand you (and I) know how to get things done using Git, but as a society and a technically community, we should strive to make things better.
I feel like the entire concept of version control is "unintuitive", especially when you have multiple people working on the same codebase.
What's worse, is that a lot of people who seem to be asking for the same workflows actually have slightly (or significantly!) different conceptual models of what they want, so we end up in this weird place where we think we all want the same thing but actually don't.
If anything, git has clearly demonstrated that this is a complex space, and its perceived unusability stems from the fact that the operations it supports simply map onto basic graph operations.
I think what you say is true but git exacerbates it significantly by layering ultra confusing terms on top. It's slowly being fixed in small ways but things like making "checkout" have multiple meanings both of which conflict to conventional usage in other version control tools is really inexcusable and nothing to do with graph theory.
I'd argue that DVCS is unintuitive as a concept and Git just spawns from that. If you know graph theory and understand concepts behind DVCS and asynchronous workflows, Git just isn't hard, but that's minority, including actual developers.
Switching Git to Mercurial, or pretty much any other actual DVCS ain't going to make life of artist or someone tech-clueless any better, because while UI might be improved they still don't know what exactly they are doing or why
Agreed. Are the people defending it forgetting how often beginners end up in seemingly arcane states and need to just check out the branch again to return to sanity?
I dunno. Isn’t that what happens when you learn something?
When learning to program, you end up in arcane states. When learning languages, you end up in arcane states. Even when learning how to drive, I ended up in arcane states.
Obviously a bit of hyperbole, but when hopefully when you learn it and end up in weird states, you have a companion helping you to correct course.
I'd imagine they'd do the same with any other DVCS. The concept of 2 people changing file that then needs to be merged is already hard enough for some, add distributed and you're in for a mess.
From my experience as sysadmin the people having problem with it also highly correlate with people that just chmod 777 on server if something doesn't work and they don't understand why...
It’s also a UX nightmare. I work with tons of artists and engineers from the games and film industry.
Teaching git to an artist is painful. UIs work, till they invariably fall apart and then they’re confused again in the command line. Also most UIs can’t abstract the ideas to a good easy system.
Even a ton of very experienced engineers fall over when you touch rebasing etc…
Now people will say use Perforce. Well that has its own issues around branching/streaming and integration for code etc… plus you’re tied to their systems, and I’m not convinced their UX is great either, just better.
Plastic SCM seems to be the best so far but I haven’t really put it through the paces much.
Anyway I guess my point is: git is a fantastic technology marred with bad UX. It’s much like GIMP or Blender back in the day that had terrible UX as well, but have since improved greatly.
I’d love to see a rethink of the git UX at the UI level, that can guide even the most novice programmer through everything easily.
Edit: also I know invariably someone will say to make my own Ui instead of complaining. I’ve tried. I’ve done some novel things but it’s really hard to do from a top down level without also rethinking some of the base interaction model. That’s a battle I think needs a lot of effort across the stack first.
I'd argue you're using the wrong tool for the job. Git isn't designed for art assets in games, it's design for text based source code. Everything else is an afterthought.
Games, especially AAA games, have 10s or 100s of terabytes of source assets. Git was never designed to handle this. git-lfs is a hack to try to help here but it's bolting on a workaround for a system that was never designed for managing art assets.
It's also not designed to handle the fact that generally art assets are not mergable and so it doesn't handle coordination of editing assets (making sure 2 artists don't edit the same asset at the same time)
No amount of UX is going to fix that git is the wrong tool for managing art assets.
update: Googling for gamedev asset management this came up
I’d agree if I was only working in games. But there’s lots of nuance.
Firstly, I’d already mentioned perforce.
But secondly , and this is my fault for not going into detail, I never said it was a game. There’s tons of software engineering categories with 3D art that are software heavy , so git wins out due to the ratio of engineers to artists.
Third, git with lfs configured from the get go isn’t that much worse than perforce with the exception of shallow and partial checkouts still being a pain. Otherwise perforce brings its own pains and UX hurdles. Streams and reviews for example are really rough to work with compared to git.
Lastly there’s just so much infrastructure around git. From hosting to CI/CD. Having multiple VCS is painful
Agree to disagree. Saying git exists therefore it should be used it like saying is all you have is a hammer everything is a nail. You wouldn't use a hammer for a screw and you shouldn't use git for art assets.
git-lfs only solves storage. It doesn't solve the 50 other things that are special about art assets.
Lastly there’s just so much infrastructure around git.
All that infra has nothing to do with art assets though. Again, looking at art as nail because all you have is a hammer (git)
You’re again misreading what I’m saying. At no point would anything I mentioned be described as only considering git as my only hammer.
It’s easy to say “you should use XYZ” in a vacuum but there are often always tons of other reasons to pick a solution.
Thanks for your thoughts, but they assume I’m not well versed in the domain enough to make the correct decisions for my teams.
It’s also besides the original point that git has a very poor UX. Like yeah there may be things with better UX, but that doesn’t lessen the original criticism nor does it mean one should switch just because of it.
Eh, just dust off graph theory and read Git Book like 3 times and you'll be fine /s.
But DVCS is just a bit of complex system to get. "Good UI" in this case is just finding enough common use cases and making them easy that the average mortal won't have to think what commands they type actually do. Case in point:
> Edit: also I know invariably someone will say to make my own Ui instead of complaining. I’ve tried. I’ve done some novel things but it’s really hard to do from a top down level without also rethinking some of the base interaction model. That’s a battle I think needs a lot of effort across the stack first.
as did many other. DVCS is a distributed system(doh) and those generally make reasoning hard for ones not used to thinking that way.
Aside from that I think git would benefit greatly if it had --explain command that would try to explain in human terms what the command you're trying to run actually does
The fact there is no de-facto UI for people that don't understand tech IMO points to the problem being just too hard to grasp for average person.
DVCS of any kind just requires certain bottom level of knowledge, if you don't have it you will just get yourself into trouble regardless on how good UI itself is.
Yeah ... I made an effort to try and understand Git as best as I could and have been quite comfortable in it for a while now. The CLI is not intuitive I get that but there's a lot of combined knowledge out there to get one out of a jam and good best practices like git-flow and such so not sure why all the angst here.
Even with some improvements, git UI sucks to this day. Linus didn't care much about the chrome and had a special aversion against anything that smelled of SVN, including the names of the commands that actually made sense. And the worst thing is that Subversion wasn't even half bad - it was just bad for Linux kernel development. Most companies could easily use it today (and some still do).
Additionally, Mercurial with its consistent UI is/was (imnsho) far superior to Git. Git won mostly because GitHub was lightyears ahead of everything else (and in many ways still is), not because git is any way better than hg.
I've used Subversion, Git, Mercurial and a few others to test them out....honestly although Git is better than Subversion, I like Git the least and I've been using it for about 6 years. I don't like its interface, weird command names like remote add origin, fetch/pull/clone, clean -nx, arg.
It's a very frustrating piece of software whose commands seem more reflective of it's design rather than what it was designed to do.
Three things that I feel are true about git's model:
1- the model is not intuitive to beginners. There's a really tough learning curve.
2- the model is powerful but leads to a few specific workflow. If you don't have the same mental model and don't want to use those workflows, you will have the "misery" the author describes. Otherwise, you'll be perfectly fine.
3- no one has yet to do a great job of describing that model and workflow visually.
The author's "features from the future" feel to me like they just haven't gotten a good feel for the model. That's why they are miserable. That's partially because git's model is hard to learn, and partially because after all this time they still haven't taken an hour to deeply learn it.
I disagree. The model is intuitive. It's just that Git dresses it up in confusing language, a terrible CLI and a gazillion half baked GUIs. It doesn't help that lots of people recommend not using a GUI which is terrible advice for learning.
Btw I would recommend GitExtensions for learning Git. It has the most intuitive interface I've found. For example it lets you browse the files at each commit which really shows how commits are snapshots, not diffs.
Git model is intuitive until you have to deal with merge conflicts, rebasing etc. Are you judging with that experience?
> For example it lets you browse the files at each commit which really shows how commits are snapshots, not diffs.
This is exactly the problem I mentioned. For one, each commit is a snapshot in the sense that it shows us a snapshot. Internally, it's a bunch of hashed and interlinked files. Git only collects them to show us a snapshot.
But you probably knew this already. The real confusing part comes when you have to amend a commit, merge branches, interactive rebases, etc. The changes between the commits are propagated as patches. Even the merge algorithm uses a 3-way diff. Rebases is all about diffing and patching behind the scene. Thinking that these are snapshot operations will make the operation much more hard to imagine and predict. You should know when to use snapshot model and when to use diff-patch model in Git. This part is also rarely mentioned in Git tutorials or tools (stgit on the other hand, exposes this diff-patch idea very well)
Yes. Again, merge conflicts are intuitive (there were two different edits to the same code; you have to resolve the conflict). But yet again Git makes things difficult - using words like "Ours" and "Theirs" (when they're often both "ours"). It even gets them backwards in some cases!
Rebases are also pretty intuitive. For once it's not too bad a name - you take all the changes in a branch and reapply them to a new base commit. Re-base.
> Internally, it's a bunch of hashed and interlinked files. Git only collects them to show us a snapshot.
That is the snapshot. It's deduplicated but it is still a snapshot. I'm not sure what your point is here.
> Thinking that these are snapshot operations will make the operation much more hard to imagine and predict.
It really doesn't. It just means you have to describe what things do properly. Rebase calculates the changes from one diff to another and tries to apply those changes again from a different starting point. Easy no?
> and partially because after all this time they still haven't taken an hour to deeply learn it.
I've spent a fair amount of time working directly with the object database, working with the latest Git features, filing bugs to upstream, working on my own source control extensions, working on successor version control systems (Jujutsu), attending and presenting at Git meetups... It's difficult to be more of a Git power user without being on the core developer team itself.
> If you don't have the same mental model and don't want to use those workflows
The workflows in question support the Linux mailing list patch workflow, which are described in `gitworkflows`, and are indeed what Git was originally created for.
Is it possible that maybe you haven't gotten a good feel for the model?
> The author's "features from the future" feel to me like they just haven't gotten a good feel for the model.
The author is apparently behind[1] a sucessful alternative UI to Git. It seems safe to assume that they are way beyond merely getting a feel for the Git model.
The Bad-UX denialism has really gone too far when authors like that are dismissed over the old You Just Have To Understand The Model talking point.
Apologies if this is only tangentially related, but it's a thought I've often had:
When I went through my university degree (which, admittedly, was over a decade ago), the skills and/or training for the day-to-day tools of software engineering - like git - were nearly never taught in a dedicated way in the same approach as concepts like data structures or algorithms. With degree in-hand the average graduate would probably be more comfortable reversing a linked list or estimating the O(n) of an algorithm than performing a git rebase. Yes, the latter is technology-specific rather than a generalized CS principle, but I would have to imagine that some capstone-type work would really spend time properly training a white-collar worker deeply on a standard few industry tools.
I'm not saying that the author is wrong, because git is indeed deviously inscrutable at times. However, after my twelfth or thirteenth failed merge or rebase, I really _dedicated_ some time to figure out what the hell git was doing from the ground up - which wasn't easy or quick - but I haven't felt truly mystified and incandescently angry at git since. It probably isn't fair to expect every Joe Software Engineer to spend that kind of time on each tool they're expected to use (I'm a masochist and enjoy doing it) but it bums me out to run into the occasional software engineer who never had the opportunity to engage in deep learning and/or practice about their closest tools like a nurse with an ultrasound machine or a court reporter with a stenotype. In a more perfect world a well-rounded software engineering education program would give people space for that, but we're left with "squeezing it in-between sprints" or "on weekends" because it's hard to imagine a company granting people ample time for professional development that doesn't transparently inflate OKRs.
Maybe my anecdote is out-of-date now and the situation is better, but I do still feel like most of us have had that "coworker had to blow away their local repo because git became too tangled" experience in recent memory. I also sort of assume that, in a paradoxical kind of way, code bootcamps may do this type of thing better, but I don't have that experience to draw from.
1) thinking university degrees are meant to prepare you for jobs. This is not why higher education institutions like universities came to be centuries ago. Universities are about sharing knowledge and researching. I would even debate 99% of jobs requiring a degree don't really, software development being one of those. Hell, one of the most important and famous chief surgeons in Italy, with various high impact papers. Was found to never have even started a medical degree.
2) Of all the degrees, I would safely say, SE and even CS are among those closer to day-to-day tools at work.
3) Extracting your experience and assuming it to be similar to those in other colleges, years, countries.
Git always seems to be explained terribly, and I wonder why that is.
To me it feels straightforward now but I graduated the route of rcs->cvs->svn->git.
I think people get tripped up by the multiple layers there are between remote and local repositories. Remote->fetch->pull brings data to you. Save->add->commit->push sends it back. Then there's branches to add another layer of safety.
Git being difficult is a "hilarious" meme just like exiting Vim, or writing c++. Unfortunately people hear that and have given up trying to understand it before they've even tried.
The best git UI is git from command line. There are edge cases when additional tooling on top of git will screw you up because it makes assumptions on what you want to do. I want to avoid those edges.
Git is pretty easy to use but people tend to overcomplicate it. Just push changes to your branch. Merge when ready. And keep your branch up to date with your main branch. Easy.
If you want to use DVCS as DVCS you gotta understand the details. People don't then get into trouble. But to be fair git will do exactly what you ask it to and not warn about some pitfalls and there is also no "tell me what this operation would do" so it's easy to get into nasty state if you just copy commands off internet.
Unless your company has a huge fixation with git history you really don't need to know much more than basics one can pick up with ease in what, few hours?
I never rebase in my life, I just merge the target branch and call it a day, most companies only track merge commits anyway so history is the same.
If you think that a git rebase is overcomplicated, rather than a fundamental primitive, then you missed an important part of the tool. And phrasing it this way is an insult to anyone who really tried to understand the tool - kind of like the nerd badge in schools.
Git rebase is fundamental to Git in many ways. It is also easy in many ways. At the minimum, it makes it easy to make mistakes while experimenting much less of a hassle, since the commit chain can be cleaned up later.
However, the point here is that git rebase is more similar to what the kernel developers and git developers intended to do with the tool, compared to the commit-merge workflow. There are two aspects here:
1. The tool developers want every commit to be feature-complete and that it won't cause broken builds at least in the master branch. This is impossible to achieve in the regular commit-merge workflow.You need to add the interactive rebases to achieve the goal.
2. Git hides something behind the snapshot model it claims to be based on. The commits themselves are snapshots. But the way changes are propagated between commits (like stashing, commit amending, merging, cherry-picking, rebasing, squashing, splitting, etc) depend on plain old text diffs/patches. It takes a while for beginners to realize this. The kernel devs were using emailed patches and tools like quilt patch manager for nearly a decade before they created git. You can still see the influence of diff, diff3, merge and quilt in the design of git. Knowing this makes you much better at predicting the outcome of these operations. Blaming the tool without trying these techniques is very uncharitable indeed.
I've been learning Pijul these days. All those complicated operations are condensed into a small set of commands in pijul. For one, it concentrates on patches only. I feel that part of Git's complexity is its mixing up of snapshot and patch model into a single program. Git didn't have the luxury of these diff alogrithms back then.