Things I wish everyone knew about Git (Part I)
blog.plover.com
blog.plover.com
Mercurial calls these bookmarks which IMO is a much better name because it works exactly like real bookmarks (in books, not browsers). A git branch feels a little bit like a branch of a tree because each commit points to their parent. Therefore, you don't need to track the entire sequence of commits in the branch but just the commit at the tip. I think if they'd had named only this concept better, Git would've been way easier to grok.
I wouldn't usually nitpick like this but given that the entire point of this article is it matters to get the basic concepts right, I figured the author might want to get this basic concept right.
Potentially more than one.
Humans really do handle treating changes as a sequence. I wonder if this was really necessary or could have been serialized.
(IIRC, from some version of git from about 6 years ago)
Graph log visualisation was certainly fairly difficult to make much of, but it wasn’t generally intended to be made much of, since it was basically a deployment implementation detail.
For example, consider this very ordinary-sounding phrase that I just picked out of the git-rebase man page:
> If the upstream branch already contains a change you have made …
I don't think your account can explain what is meant by this.
In any case, I didn't make the choice casually, thoughtlessly, or from ignorance.
The talk has an abbreviated version: https://perl.plover.com/classes/git-tips/samples/slide018.ht... It's an illustration of just one example of this: If we rebase "branch X" onto commit B, we rebase only the three green commits. But if we rebase it onto C, we consider X to contain the two dark blue commits also.
Are the dark blue commits part of branch X? It depends on what you're trying to communicate.
However, the history of a commit is always the entire tree of ancestors. This entire tree is the precise definition of what constitutes all the commits of a branch.
Thus while I agree that it is not wrong to view a branch as a bookmark, I also think that attempts to nitpick the man page's use of the term fall flat here. "Commit contained in a branch" just means: "commit contained in the history of the commit the branch currently points to." and isn't ambiguous.
Obviously, and if you got the idea that I thought you did then I apologize for that.
Anyway, the git docs aren't exactly known for getting the nuances of its own concepts right, which adds to the general confusion.
That said, I think I see your point now: it's the same as how a reference to a linked list is actually just the head of the linked list, but you still call it a list and not a head.
I have to admit that maybe I didn't see the forest for the trees.
And am I also the only one who still knows how to do things in Mercurial but not how to take the corresponding action in Git? I mean, they're things I haven't had a reason to do in years, but it has some psychological cost to feel like I'm using a system I'm worse at.
Mercurial is opinionated. It's had to adopt the Git way slowly, grudgingly.
The only big difference I recall Git winning on was in third party tooling and Git supporting more than two parents merging.
1) We used some super crappy Clearcase version control system. It was easier to layer Git on top, letting us have a VC on top of a VC. I can't remember if it was impossible, or just easier to do in Git.
2) Conflicts did better. We made kind of torture test of merges and put both systems through. Git was able to resolve more out of the box.
3) Speed of operations, I think Git was a bit faster out of the box.
None of this was about Github, as it was comparing self hosted HG vs self hoted GIT.
Quibble: Git didn't win. Github won. Git was simply the parasite on the Github host.
However, I feel just like you. Mercurial is just so ridiculously easier to explain to people.
I really don't understand what it is about Git that seems to prevent anybody from coming up with a sane UX for it.
That's the problem. Git has a sane UX. The only issue is that a lot of people who doesn't understand it, write silly tutorials where they spread their misconception about it. The real issue is the poor quality of tutorials over the internet that mislead a lot of people.
Or git rebase
It's two simple command
On that note, I have written something like this, but it is not something I think belongs in the standard toolbox. It is a tool that applies "formatting" fixes to a topic, preserving history topology. However, it requires some automated tool to be able to perform the edit so that any conflicts can be resolved by running the tool to perform the edit (typically clang-format or autopep8, but sed or something like that is also a candidate). I don't know that requiring your edit to be expressed in terms of sed is suitable for such a "simple" tool to replace rebase.
So for the majority of users, they wouldn't have to even know about rebase until they have quite a bit of experience with git (and programming in general). It's a better learning curve, especially considering Git is now being taught to beginner programmers.
A `git edit` command is not as powerful as `git rebase`, but this is just how UX works. You expose a smaller simpler set of features at the front, and then (if you aren't Apple) allow the users to do more advanced low-level operations if they need to.
I guess we just disagree on how shallow or deep any problems `git edit` tries to hide are in practice and therefore how much convenience it actually saves.
Here we are. You can't tweak a commit in git. You want to recreate a new one. That's why UX is awful, because there is a permanent confusion about what git does.
We can either posit that the people who made and use Git are substandard, or we can posit that there is something fundamental about Git that makes writing such tutorials difficult.
Explicit rename tracking is a mistake though. I think Linus got that one right.
This is not entirely true, because it is perfectly possible to create commit graphs in git in which there is not a single well-defined branch for some commits. So just knowing the branch labels at each tip is not sufficient to assign a single well-defined branch to every commit in the graph.
Mercurial branches don't work like this: they are actually stored as part of each commit, so even with ambiguous commit graphs each commit still has a well-defined branch.
> Mercurial branches don't work like this: they are actually stored as part of each commit, so even with ambiguous commit graphs each commit still has a well-defined branch.
I wonder which operation would not be possible with Git had Git gone that way. And hence I wonder too what's that operation that Git can do and that Mercurial can't.
Honestly switching from Mercurial to Git this weird "branch that aren't branch at all" was the single most WTF feature of Git.
What do you mean? Git branches are branches. What is a branch for you? And why git branches aren't?
Can you elaborate on what you think branches are a better reference to? What operations or concepts are better expressed in terms of them? I think I'm at the edge of an epiphany here ... but I'm not quite groking it yet.
A commit is as much a branch as a head of a linked list is both a node and a list.
I think 'branch' is fine.
True, but in the past majority of cases parent commits in the branch (commits from leaf to the last ancestor that has only one child) would be semantically very related so this understanding is not that bad (so long as you remember a branch is a commit for git operations).
I've read this about git several times and certainly felt it. My question is why hasn't anyone come along and fixed it? Git has the plumbing vs. porcelain separation. Why hasn't someone written new porcelain that makes git as intuitive as mercurial, subversion, etc? This seems like a similar situation as dpkg/apt. The underlying design has been settled but we desperately need a better interface.
> Git has an elegant and powerful underlying model based on a few simple concepts
My second question is, if the underlying model is so f*cking elegant, how did it lead to such a confusing interface? This isn't so much me griping about git (although I am) but more a curious case for design theory. Would love to read serious analysis. I can't offhand think of another piece of software where "the model is elegant but the interface is confusing" is such a common critique.
There's been dozens of "replacements"/frontends/guis for git, off the top of my head: gitless, magit, tortoise git, gitkraken. Heres a whole mess of em: https://git.wiki.kernel.org/index.php/Interfaces,_frontends,...
> My second question is, if the underlying model is so f*cking elegant, how did it lead to such a confusing interface?
I think this is 66% because the operations are on the tree/nodes themselves, and not like, on "versions", branches, or some other skeumorphic abstraction. It's very bare metal. If you know how the command operates on the tree, you know how to conduct the actual action desired. I think the rest is due to cruft/familiarity - once you build that mental model, it works extremely well. So it's vi-like with a steep learning curve and arcane interface, but once you "git good", it's phenomenally productive.
I've used svn and git extensively, but after getting very used to git, i tried working on a project that used mercurial and walked away completely confused by how it works. With "branches" being completely different beasts that i couldn't understand and unsure when it was appropriate to use bookmarks instead. It completely baffles me that people find it better than git's super straightforward dag-of-snapshots model and I reject the idea that it is simpler or more intuitive.
Although note that unlike git, you don't need to use Mercurial's bookmarks since Mercurial is perfectly happen to let commits sit around without having names pointing to them.
Dozens have, but by the time their replacement porcelain gets anywhere near useful they’ve attained a grasp of the plumbing more than good enough they don’t need it anymore.
> My second question is, if the underlying model is so f*cking elegant, how did it lead to such a confusing interface?
Mastery of structural elegance doesn’t mean you have also mastered interface and experience. In fact it’s often not the case.
> I can't offhand think of another piece of software where "the model is elegant but the interface is confusing" is such a common critique.
Every database. The relational model is a beautiful thing, sql is a horrendous shit-show.
Amen. We probably disagree on if we need less abstraction or better abstraction though.
For all the griping that git gets I really think it could be much worse. It's a somewhat inelegant shrink-wrap over its data structures but at least I can get at all the pieces I need.
I get that SQL works well for ad-hoc analysis and business cases, and a query planner is super useful there, but for service to service calls I'd love a language that let's me refer to the tables, the b-trees, row-ids, and lets me tell it what to do.
Quite Insane :)
Ok, more helpfully, what possible value would you get if the DB gave you access to those?
Because the model is simple and easy to understand, and you get a lot of power from understanding it. Whereas opinionated porcelain that tries to insulate the user from the model will tend to fail in obnoxious ways and will not serve the user.
Really, there's objects, there's commits, then there's a couple of methods for symbolically naming commits (branches and tags) because humans need symbolic names (because we can't memory SHA-1 hashes, or any hashes). Object and commit hashes function as pointers or inode numbers. Symbolic commit names function as hard links.
If you understand the Unix filesystem, you can understand Git.
Everything else follows from these things.
Merges create new objects referenced from the merge commit.
Rebase is just a script around cherry-pick.
Cherry-pick is just applying a delta from a commit and then re-committing.
Everything is copy-on-write except the symbolic names (branch names, tag names).
There -- I've just told you everything you need to know about the model. And all of that trivially carries over to the UI.
The problems with git are not the commits and the DAG. It's all the ancillary stuff that's inconsistent and confusing.
My workflow here would be something like:
git checkout -b save
git commit # save staged changes
git add .
git commit -m WIP # save unstaged changes
git checkout -Next question.
Note that the analogy to filesystems is not exact. The point is that you can understand higher-level operations in terms of lower level ones / gain insight into higher level operations from knowledge of the lower level concepts. As opposed to the cognitive burden of incomprehensible magic, where every time you get in trouble you've no idea what to do.
That’s trivially not true from its conflict resolution abilities. A cherrypick is a merge which does not create a merge commit, it’s a lot “smarter” that “git show -p | git patch”
This is the consequence of elegance. Elegance at one level usually is characterized by being very data-agnostic, very workflow-agnostic, etc. This leads to anything built on top of it to be so generic its unusable or at least very awkward.
Pretty much everyone who works with git daily has a set of script to do the actual day-to-day work. The git command is too awful to use otherwise.
It's really not as hard or cumbersome as this comment section would have you believe
> I've read this about git several times and certainly felt it. My question is why hasn't anyone come along and fixed it? Git has the plumbing vs. porcelain separation. Why hasn't someone written new porcelain that makes git as intuitive as mercurial, subversion, etc?
What about svn is intuitive? It was never intuitive to me. It always felt confusing.
Trying to deal with any system without having a mental model (even if high level) of what's going on will always cause problems. How do I know if `svn update` screws up my uncommitted changes? I never felt safe with svn because I had no idea what the commands could do to my files.
> My second question is, if the underlying model is so f*cking elegant, how did it lead to such a confusing interface? This isn't so much me griping about git (although I am) but more a curious case for design theory. Would love to read serious analysis. I can't offhand think of another piece of software where "the model is elegant but the interface is confusing" is such a common critique.
This is actually pretty common. You just don't notice it when you are used to the interface.
The unix file system and command line tools come to mind.
> Jujutsu is a Git-compatible DVCS. It combines features from Git (data model, speed), Mercurial (anonymous branching, simple CLI free from "the index", revsets, powerful history-rewriting), and Pijul/Darcs (first-class conflicts), with features not found in either of them (working-copy-as-a-commit, undo functionality, automatic rebase, safe replication via rsync, Dropbox, or distributed file system).
> Compatible with Git > > Jujutsu has two backends. One of them is a Git backend (the other is a native one 1). This lets you use Jujutsu as an alternative interface to Git. The commits you create will look like regular Git commits. You can always switch back to Git.
In using it, you're always confronted with deltas, so it seemed that was how it worked. The command structure didn't correspond at all, and was thus very confusing.
Git is really a contents addressable archive disguised as a version tracking system.
This is a great take. I think I got lucky that I went from "copying whole directories to save my work before a refractor" directly to git without leaning svn or anything else first.
Treating it as a snapshot management/copy-on-write content addressable storage + diffing utilities is a perfect way of thinking about it. I always wished LVM snapshots had git's CLI.
I also try to start them off with gitk/`git gui`, which make it a lot easier to understand what’s going on (“ok, so here you see a diff with the changes you made. Now you stage the file, and it moves down here. You can put it back by unstaging it, but for the moment let’s commit it. Now in the graph you can see your new commit, with a line pointing at the parent, and your branch pointer moved along with it, but the origin/branch pointer stayed behind, so to get that to move we need to push the new commit to the remote...”)
If you just learn the mapping of those concepts to Git's vocabulary, you really don't need to memorize all the commands. In the odd case, you can just look up the docs. Nodes are commits, references are either branches or labels depending on whether they stick to leaf nodes or any other node. Your working tree is the current state of the repo in your filesystem, and staging is how you assemble commits.
I've seen it leveled against emacs, git, vim, etc. It's kind of sad.
I suspect that "attempts to explain something in an easy (but subtly wrong) way" have fueled it with regards to git.
It's like being handed city maps of LA and NYC and told to drive from one to the other.
2) Every tutorial and book leans into the horrible vocabulary, and the metaphors they use to "simplify" and "explain" it only make it worse. All of the analogical baggage is far more complicated than a straightforward description of the data structures.
It took an embarrassingly long time for me to understand that HEAD was just a pointer at the branch or commit you were currently working with (I wish somebody would take that "detached HEAD" terminology out back and shoot it), and that a branch was just a tag that, if HEAD is pointing at it, will move to point to a new commit that you make.
That's because "HEAD" and "branch" are stolen terms crowbarred into something quite different than CVS.
edit: the actual Git book from git-scm.com is not bad at all, but most people aren't learning from that.
1. If I've partially staged some changes, why can't I stash and unstash them and get back to the same state?
2. How come stashes are sort of like commits but sort of not? I've managed to get into a state where I had a stash that couldn't be popped because it was in the wrong format - how can I tell when this will or won't happen?
It's super intuitive, there's buttons that say exactly what they'll do without me having to worry what underlying commands it's running, and the best part is the merge conflict resolution UI that lets you go file by file and has a 3-pane split for existing changes, merged file, and incoming changes. You can select the arrows that are drawn from one pane into the center to bring those changes into it, X to ignore those changes, and the center is completely interactive like any other text editing area in the IDE so you can just copy paste from each side and fix it yourself.
I basically don't ever bother with git from the command line.
`git config --global merge.conflictStyle diff3`
If you ever wanna go back to the command line, your life will be much easier.
> It is very hard to permanently lose work.
Unfortunately, this is not quite true. Git checkout will silently and irretrievably clobber all the changes in your working tree [UPDATE: if you do 'git checkout [path]', but that is not an uncommon thing to do.]
It is true that it is very hard to lose work that you have committed. But even this is not necessarily a good thing if, for example, you accidentally committed something that contains sensitive information that you want to delete. (And God help you if you have pushed such a change upstream.)
The sad fact of the matter is that while the underlying data structures are beautiful and tremendously useful, the UI/UX is a dumpster fire.
It's actually not that hard to put a different UI/UX on top of the core. I'm kind of surprised no one has done this.
Not by default it won't.
It can do that, if you explicitly run it with the options to checkout a specific path. But why would you do that if it's not what you want?
I was, at one point, in the habbit of running "git checkout ." after writing some experimental code. Several times a day, or however often. So of course, I once accidentally ran that command in the wrong repo and obliterated some pending changes that hadn't been commited.
I used to `vim test.c` then `rm Alt-.` very very often. Until one day sure enough I'm in the wrong directory, and I actually saw `Alt-.` complete the filename of an important file, but the brain veto latency is slower than the muscle memory twitch and my pinky continued on over to the Enter key.
I blame only Dotan and changed my work habits. Bash had nothing to do with the incident.
These are pretty light asks.
But it is an argument supporting the claim being discussed: that the statement “It is very hard to permanently lose work” is not quite true.
That’s what makes it easy to make that mistake, and lose data. It’s safe to use until it suddenly isn’t.
Fair point. I've update my comment to clarify.
> But why would you do that if it's not what you want?
Because sometimes it is what you want. The point is, if you happen to do it when it's not what you want, you're hosed. So it is simply not true that "It is very hard to permanently lose work." It is, in fact, quite easy under certain not-uncommon circumstances.
If you give people a way to get to a clean slate it removes a significant amount of the learning curve. In my experience, push/pull/fetch/log/diff are easy enough it's only really merge/rebase management that gets people caught up. Giving people a short fuck up -> undo -> retry cycle lets people learn pretty quick.
That's it. Know that, live that, and you'll never lose work because of Git.
git checkout can also nuke changes from both working copy and staging area. `git checkout <path>` will nuke working copy (and auto-completion is likely to give you a path when you were looking for a branch), `git checkout <ref> <path>` will nuke both. No --force required in either case, so let's not pretend that you can't lose changes without a scary-looking flag like --force or --hard.
Not explicitly.
`git checkout ref path` implies `--force`, since you're being specific.
I would prefer if Git could keep a GCed pile of saved workspace changes every time you force checkout/reset.
But for the love of all that is good, stop using `git checkout`/`git reset` in the few ways they hurt.
The entire point of that command is to discard local changes.
There is some risk of getting the different forms of checkout mixed up, though, so prefer using switch and restore instead. As far as I know, the only use case of checkout not covered by other commands is checking out a commit that doesn’t have a branch attached to it.
I think that's arguable, but it's neither here nor there. Someone who is not well versed in git arcana will be surprised that the level of risk associated with 'git checkout [branch]' is radically different from 'git checkout [directory]'. I think a lot of people will learn this the hard way, especially if they have been told "It is very hard to permanently lose work." It's not true. Permanently losing work is as easy as being careless with git checkout.
I disagree that it's a difference in the level of risk. There's no "risk" that git checkout [path] will discard your uncommitted changes, it's a promise and a certainty.
That said, I agree that the breadth of largely unrelated functionality smushed into git checkout is surprising, but it's also one of the few things about Git's user interface that actually has been addressed by new subcommands.
It seemed to me, linus and the initial git architects just kind of slapped names on operations as features grew organically over top of the model. To early adopters, all of it made sense. Yeah, someone new looking in from the top down will be bewildered.
So usage-wise git was familiar to someone familiar with e.g. SVN right from the beginning.
https://news.ycombinator.com/item?id=31874308
Some that looked interesting:
* https://learngitbranching.js.org/
* https://github.com/blog/2019-how-to-undo-almost-anything-wit...
The casual group may include people very young/old, people with no (significant) background in programming, people that had little formal education in general, non-English speakers, people with cognitive limitations.
When you approach Git like that, neither the commands nor the concepts behind them make any sense.
Saying something like "see, git is just a merkel tree of immutable objects with a unique hash id and a commit is a blah blah..."
...makes no sense whatsoever to the casual group. They are alien words and concepts that are not relatable to the actual task: I just want to version manage something.
Yes. For me the rescue was Charles Duan's git tutorial: Understanding Git conceptually. https://www.sbf5.com/~cduan/technical/git/
> you can only really use Git if you understand how Git works. Merely memorizing which commands you should run at what times will work in the short run, but it’s only a matter of time before you get stuck or, worse, break something.
The original claims
> It is very hard to permanently lose work.
I disagree. So I run a git reset safety net https://gist.github.com/chx/85db0ebed1e02ab14b1a65b6024dea29 it saved my bacon quite a few times. (Bonus git cd command. It's useful.)
Anything that ends up in a commit should be recoverable (on the same local git repository, that is), no? The main things that can forever clobber your work afaik is git checkout -- <path>, which will perhaps a little unintuitively just clobber over whatever is not committed.
Technically no, due to GC.
a) Don't tell people about stash. All Commits Everything.
b) All commands that change the working directory or branches should fail on uncommitted work and ask you to git commit. It already does this for untracked changes.
c) Show people show git branch BACKUP (requiring a commit) + git reset --hard BACKUP will always get you back to where you started safely.
I might very well be negatively biased but I'll admit that the whole "GIT's data model is beautiful" makes me roll my eyes every time. I've read through several guides and they have not helped me at all; they even confused me more.
GIT is a tool for managing versions of files. It must be blindingly and painfully simple and all the special cases should be named much better than they are right now.
The fact that they are not is just making me impatiently wait for when GIT's mind-share stealer will come around. Or I dunno, I might just start using Mercurial CLI on top of it and just give up.
Commits are immutable snapshots of the repository
Branches are named sequences of commits
Every object has a unique ID, derived from its content
I would list them as: Every object has a unique ID, derived from its content
- and every commit id depends on its ancestors' commit ids
Each commit has an associated snapshot (file tree) of the repository
A branch is a named reference to a commit
- the referenced commit changes with addition/rebase/amend of commit(s)
Not quite as compact or elemental but a usably granular mental model.If you want to learn how git works you can read about it, or merely look at the small text files inside a .git directory.
To make it worse, correcting mistakes ALSO is something that's not done regularly-- so that becomes an obstacle as well.
Why is this important? Because code review is about reviewing the changes and applying patches in a different context to where they were authored. If I fix a bug in my repo then you should be able to apply my fix cleanly to a repo in a quite different state that mine was in. We can work on different things in a decentralised way and yet still collaborate.
Most people of course don’t work like this. Most people in 2022 will literally share a parent commit from a central repository. They push and pull over the net instead of emailing patches. Their trees are in sync a lot more than the days of patch emailing yore. (Although emailing patches is still used by people who need to exfiltrate a change from some system not blessed with full access credentials to do a real push.)
The thing that does still hang around is the idea of a dissociated patch being the unit of a review. Some code review tools don’t really get this right — Gitlab in particular still muddles up the idea of a merge request and a commit. A merge request has a title and a description but so does a commit and yet they are kept separate. You view an MR’s changes as one big patch and these may or may not bear any resemblance to the git commit or commits and their own titles and descriptions. It is as if GitLab’s authors either purposely or naively ignored the idea that git was designed to think in this way from the ground up, and so they implemented a patch-like thing of their own, on top.
I’ve also never embraced the idea of commits that are for public consumption and those which are not. In my model, there are no feature branches, only branches that combine different sets of patches.
It doesn’t need to be so complex and indeed if you embrace the underlying tool (on which your product is named!) gitlab based git projects would be a bit less special and a bit more like everyone else.
But I don't mind "Merge Request/Pul Request" that is basically everywhere now (github, gitlab, bitbucket, etc). It's clearly simpler for novice developer to get started with this workflow that with "patch workflow"
[0]https://en.wikipedia.org/wiki/Diff [1]https://en.wikipedia.org/wiki/Patch_(Unix)
I think it can be summarized as Linked List in reverse. New entries are always added on head instead of tail. The pointer used to track the growing list is 'branch' pointer. The pointer that is fixed to a specific node is 'tag'. Since we are adding on Head, we can have multiple nodes point to one node.
Working tree is current state of files. Index is the staging area or the buffer (if I am not forgetting) where you put your changes you are about to permanently commit.
Git is distributed system. Your repo can point to another repo as its remote copy. Can have multiple remotes. The default remote is 'origin'. When pushed, changes are uploaded to that remote repo. The remote repo doesn't have to be on a server. You can have it locally in another folder. When you push, your changes will be copied to that one too.
Edit: I don't know how merge really works, and merge issues have been difficult to resolve therefore.
I’m not talking about understanding what the working tree and index are, but how they interact under the various commands, what happens with the working tree and index state for example when you switch a branch, etc.
I’m not talking about a basic understanding of what a remote is, but about how to deal with different remotes, how to have local branches, how to push/pull only some branches vs. all branches, and so on.
Those are the things where people get in trouble and into broken states.
I found it rather obvious? Git usually tells you how to deal with it, and conflict markers are easy to understand. What could be more visible is that rerere exists, as that can save you a lot of energy if you're rebasing frequently. Also, conflicts from stashes are a weird special case, which can be confusing (but so are stashes in general).
> I’m not talking about understanding what the working tree and index are, but how they interact under the various commands, what happens with the working tree and index state for example when you switch a branch, etc.
That's also obvious, and Git tells you what happens as you do this stuff too. If it couldn't switch a branch, it tells you why; if there's an uncommited change, it's listed during checkout. I don't think I'd be able to tell how various commands interact with index without having git in front of me, and yet it doesn't cause me any visible troubles (and I'm a somewhat heavy git user).
> I’m not talking about a basic understanding of what a remote is, but about how to deal with different remotes, how to have local branches, how to push/pull only some branches vs. all branches, and so on.
I don't really understand what's problematic with those. All of the things you mentioned are really basic commands. A good tutorial could easily cover it all.
There's plenty of stuff to criticize about git's UI, but I'm very surprised that this is what you found worth mentioning.
If you are saying this in context of CLI. I have no clue. What I am saying is, if you understand the concepts and have a good GUI tool at your disposal you can solve almost all problems with ease.
I have previously used SmartGit which lets you drag and rearrange commits. It also allows interactively selecting the lines/chunks from you want to make part of commit. Same goes for resolving conflicts. IntelliJ also has a very good GUI which I use these days at work.
Something I didn't find much help with was how to squash commits which include merge commits as well. But overall, GUIs help alot if you know what you want to do.
And Managing Code Projects with Git Branching: https://www.youtube.com/watch?v=tzJDZY1x31I
Also you're totally allowed to set up private repos and run whatever dodgy commands some karma-poor guy on SO claims should sort you out and see what you end up with, or create a "rewritten history" scenario that everyone has always been warning you to avoid (forbidden fruit...).
In summary: Read the docs and git grokking!
There is 'git mv' for that. I have found the best way is to create new directories then use 'git mv' on the files.
Merge after that... If that doesn't work I cherry-pick.
If that doesn't work I copy changes out of the folder, reset and copy back in.
Somehow I've gotten by for years fine.
Mercurial is dead.
> Although Mercurial was not selected to manage the Linux kernel sources, it has been adopted by several organizations, including Facebook, the W3C, and Mozilla. Facebook is using the Rust programming language to write Mononoke, a Mercurial server specifically designed to support large multi-project repositories.
Mercurial @ Google:
> Speaking of Google, their Mercurial rollout on the massive Google monorepo continues. Apparently their users are very pleased with Mercurial - so much so that they initially thought their user sentiment numbers were wrong because they were so high! Google's contribution approach with Mercurial is to upstream as many of their modifications and custom extensions as possible: they seem to want to run a vanilla Mercurial out-of-the-box as possible. Their feature contributions so far have been very well received upstream and they've been contributing a number of performance improvements as well. Their contributions should translate to a better Mercurial experience for all.
https://groups.google.com/g/mozilla.dev.version-control/c/hh...
GitHub is a fine place to stash free code for free. Adding Linus Torvalds' good name to "free storage" is an unbeatable combination for mindshare, but does not change the fact that mercurial is far more ergonomic for the typical cases, and handles facebook/google scale well enough.
To expand on this: how many engineers you work with know what actually happens in a CPU when they run a for loop, for example? How many of them need to know that? It seems to me that a lot of people are very successful at creating useful things without understanding the underlying tech. Isn't this why we built it?
Compared to a junior engineer, they have to get thrice more things right at the same time.
Knowing a tool inside out can help with this, but it's not a requirement at all. It's just one of the, a-hem, tools in their box with which they can achieve efficiency.
I am like many others in this thread. I don't care about GIT's "beautiful data model" one bit. I learned with time which commands are dangerous and I do due diligence to make triple sure I don't trip on them. With 2 exceptions for the last 10+ years (each took me half a day to fix) this has worked perfectly.
It's quite OK to stick to what you know is safe and works well (and what pre-conditions have to be met so it works well).
At this point if a customer comes around and asks me to use advanced GIT features I'll just bill them triple while telling them exactly why.
I deliver, and at least 80% of the time I deliver on time, and 95% of the time with good practices and due diligence attached. How I use GIT is my business. I've been contacted by the next contractors no small amount of times and have eaten praise for how easy to track my project's change / commit history has been, too.