1. Always use `git switch` instead of `git checkout`
2. Avoid `reset --hard` at all costs. So for the "accidentally committed something to master that should have been on a brand new branch" issue, I would do this instead:
# create a new branch from the current state of master
git branch some-new-branch-name
# switch to the previous commit
git switch -d HEAD~
# overwrite master branch to that commit instead
git switch -C master
# switch to the work branch you created
git switch some-new-branch-name
# your commit lives in this branch now :)
3. I'd apply the same to the `cherry-pick` version of "accidentally committed to the wrong branch": git switch name-of-the-correct-branch
# grab the last commit to master
git cherry-pick master
# delete it from master
git switch -d master~
git switch -C master
4. And also to the "git-approved" way for "Fuck this noise, I give up.": # get the lastest state of origin
git fetch origin
# reset tracked files
git restore -WS .
# delete untracked files and directories
git clean -d --force
# reset master to remote version
git switch -d origin/master
git switch -C master
# repeat for each borked branch
# this command exists already;
$ git switch -c some-new-branch-name
# is there a command that simply moves a branch from one commit to another without changing anything else? It feels like it should be possible given how git works.
$ git move-branch master HEAD~
There isn't one tree of commits, there are typically at least two: local and remote
Branches are not just pointers to commits, but also possibly related to pointers in the other tree via tracking.
Stash and index and the actual contents of the working directory are additional data that live outside the tree of commits. When op says "avoid git reset hard" it's because of how all these interact.
Files can be tracked, untracked and ignored not ignored. All four combinations are possible.
git update-ref <branch-name> <commit-sha>
git branch -f branch_name commit
if it's checked out: git reset --hard commit
...and for a good reason that should be apparent to anyone who understands git's model (HEAD points to a ref in this case, so if you suddenly change what that ref points to without updating the working tree you create an inconsistency).
You can do that manually of course (with `git update-ref` or even a text editor), but then you get to clean up the mess yourself.
So much for "a branch is simply a pointer to a commit"...
If a git repo was purely a collection of meaningless pointers and graph nodes, git would be a graph manipulation utility, not a version control system. The fact that some of those pointers have a meaning is what makes it useful and it doesn't contradict the fact that what you're working on is still just a bunch of pointers and nodes.
"error: ref in use by higher layers" makes much more sense to me in this case.
Turns out it's a tree of commits and pointers to within that tree and a master pointer that come in two versions: pointing towards the pointers or pointing towards the tree. And pointers behave very differently when the master pointer is pointing to them...
Elegant. Simple. :P
...because HEAD points to what's checked out. This pointer does not just exist and hang around, it has its semantics. Not understanding that reveals flaws in your mental model.
Besides, the side affect you find "not surprising" here is... rewriting HEAD to change what it points to. Then you ask "why would that change where HEAD is pointed". Sounds like you may be confused. Are you forgetting that a ref may point not just to a commit, but also to another ref? This is the whole idea behind branches after all, having HEAD point to a ref is exactly what makes branches semantically different from tags - if you don't understand it then no wonder you're confused.
(protip: if you find git's "pointers to pointers" confusing, perhaps because in C a "pointer" and "pointer to pointer" are separate types that make multiple dereferencing steps explicit, think of them as symlinks instead and it should become clearer - that's in fact how symrefs used to be implemented in the past)
When a pointer is in use by higher layers, a good UI will prevent you from making direct changes underneath it unless you force it or go low-level enough for it to not matter. The only sin of git I can see here is that `git` command provides you both high-level and low-level interfaces to manipulate the data structure you're working on with no clear distinction for the user.
It is surprising. You wanted to edit the value of `main` ref, yet suddenly you now edited `HEAD` too without meaning it. Bailing out and letting you actually decide whether you want to do it or not is the correct thing to do for a high-level command like `git branch` (alternatively it could ask you what to do interactively). If you don't want such safeguards and you know what you're doing, use `git update-ref` which will happily let you break whatever you want.
"git reset --hard" is "...and also change all the files in the working directory to match the new branch commit".
"git reset --soft" is "...but leave the working directory alone".
[1] https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified
Something I heard somewhere that stuck with me: git is less less of a Version Control System, and more of a toolkit for assembling your own flavor of one.
That's how it is in principle, but it seems to me that there aren't that many different CLI "porcelains" in practice. Kind of like how Knuth figured people would essentially write their DSLs on top of plain TeX, not spend most of their time in giant macro packages like LaTeX.
I think that's because most of the people that make custom tooling to support particular workflows build it into graphical (including IDE extensions, web-based. etc.) frontends, not CLIs.
git switch -c some-new-branch-name
git branch -f master HEAD~
git branch -f master origin/master
Wouldn't that copy a branch rather than moving it?
git switch -C master HEAD~
> THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
Granted, it has been in there for basically as long as the command(s) existed [2] and after 5 years perhaps it might be time to no longer call it experimental.
Still, it does seem like `git checkout` might be a bit more backwards compatible (and also reflective of the time when this website was originally created).
[0] https://github.com/git/git/blob/757161efcca150a9a96b312d9e78...
[1] https://github.com/git/git/releases/tag/v2.23.0
[2] https://github.com/git/git/commit/4e43b7ff1ea4b6f16b93a432b6...
gitg for something simple, graphical and widely available.
I think there's space for "git add ." as a didactic step. It maps cleanly to the most obvious way to understand a commit, as "here's what I've done". Bootstrapping from that to an understanding of "commits as communication with other developers" will naturally happen over time.
Explicitly adding internalizes a personal review process as inherent part of the push process, instead of something you attempt to force on top later.
It's better with a collaboration workflow that limits the span of time with expected discipline, imo.
You should avoid reset --hard because it will delete all your uncommited, and you could end up in situations where that's really bad. Using reset --keep will keep uncommited changes, and failing if any uncommited change cannot be kept.
Sounds like you might be looking for `git reset --keep`
2. "Accidentally committed something to master that should have been on a brand new branch".
This doesn't really have an analogue. Branches ("bookmarks") only move when you tell them to. If you make a new commit on top of master, it doesn't point master to it, it just lives one past the tip of master. But let's say you accidentally moved master to include the new commit you shouldn't have:
# set master to the previous commit (and reaffirm that
# you're okay moving a bookmark backward)
$ jj bookmark set master --allow-backwards --revision @-
# there is no step two, you're still editing the change you already were
3. Move a commit from one branch to another. # move the revision one-past-master on to our desired bookmark
$ jj rebase --revision master+ --destination name-of-the-correct-bookmark
# there is also no step two; technically we're not updating the bookmark
# to point to the new commit yet, but this isn't something you'd do as rote
# habit in jujutsu anyway
4. Fuck this noise, I give up: # list all the operations I've performed against the repo
$ jj op log
# restore to some previous known-good state
$ jj op restore {id}
Bonus content, translated from the article:> Oh shit, I committed and immediately realized I need to make one small change!
# move the current edits into the previous revision
$ jj squash
> Oh shit, I need to change the message on my last commit! # re-describe the previous revision
$ jj describe --revision @-
> Oh shit, I tried to run a diff but nothing happened?! # there is no staging area, all your changes are part of the repo and there is no
# staging area pseudo-commit; please understand that this still works elegantly
# with "patch-add" workflows and does not imply that large change sets can't be
# easily broken up into small commits
> Oh shit, I need to undo a commit from like 5 commits ago! # find the commit
$ jj log
# back it out
$ jj backout {id}
> Oh shit, I need to undo my changes to a file! # find the commit
$ jj log
# restore the paths provided to their contents in the given revision
$ jj restore --from {id} [paths...]
And finally there are a few things that are super easy/obvious in jujutsu that are far more annoying in git.> Oh shit, I committed and many commits later realized I need to make one small change!
# moves the changes in the current working copy into the revision provided
$ jj squash --into {id}
> Oh shit, I committed and many commits later realized I need to make extensive changes! # sets your working copy to the commit provided; later commits will be
# auto-rebased on top live as you make modifications
$ jj edit {id}
> Oh shit, I need to reorder two commits! # does what it says on the tin
$ jj rebase --revision {a} --insert-before {b}
> Oh shit, I haven't committed anything in hours but I need something from an interim change from like thirty minutes ago # look in the "obsolete log" for earlier iterations of the current revision
$ jj obslog
# restore the contents
$ jj restore --from {id} [paths...]
> Oh shit, I made a bunch of changes but want them to be in multiple commits (e.g., patch-add workflow) # choose the parts to move out; you'll end up with two revisions, one with each half
$ jj split
> Oh shit, I need to break out a change from my current work into a new branch off master # choose the parts to move out; you'll end up with two revisions, one with each half
$ jj split
# move the stuff I pulled out onto master
$ jj rebase --revision @- --destination master
# optional: name it; most of the time you wouldn't bother
$ jj bookmark create new-name --revision master+
> Oh shit, I need to make three sequential changes but roll them out one-by-one. I also might need to make fixes to previous ones before later ones are rolled out. # author a new change on top of master and name it a
$ jj new master
…
$ jj bookmark create a
# author a new change on top of a and name it b
$ jj new
…
$ jj bookmark create b
# author a new change on top of b and name it c
$ jj new
…
$ jj bookmark create c
# edit a; nothing else is necessary to ensure b and c remain as descendants of
# revision a
jj edit a
…
# author a new change as part of b; nothing else is necessary to ensure c remains
# up to date on top of b
$ jj new --insert-before c
…
# point c at the new change
$ jj bookmark set b
I've found myself using git to fix the mess in this particular instance.
$ jj file untrack {paths-or-pattern}
Alternatively if you have a bunch of files spewed everywhere with no rhyme or reason which can't be globbed or enumerated reasonably: $ jj status | grep '^A' | awk '{print $2}' | xargs jj file untrack
My post was a pretty naked attempt to showcase how much less convoluted basic operations are in jj vs. git and hopefully drum up some interest. Hopefully someone bites.
Even harder: always use "git reset --hard".
Basically don't use local branches. The correct workflow for almost every task these days is "all branches are remote". Fetch from remotes. Reset to whatever remote branch you want to work above. Do your work. Push back to a remote branch (usually a pull request branch in common usage) when you're done.
If you need to manage local state, do it manually with tags (or stash, but IMHO I never remember what I stashed and will always make a dummy commit and tag it).
Don't ever try to manually manage a branch locally unless you (1) absolutely have to and (2) absolutely know what you're doing. And even then, don't, just use a hosted upstream like github or whatever.
All branches are public.
What actual problem does this solve? For me, WIP branches only ever get pushed up if at least one of two things are true about them:
1) They're actually worth preserving, and not some experimental garbage that ended up being totally pointless.
2) I need to get them off of my local machine for disaster-recovery purposes.
> If you need to manage local state, do it manually with tags (or stash, but IMHO I never remember what I stashed and will always make a dummy commit and tag it).
I don't see the benefit one gets from putting work that's not fit for publication in a dummy commit on a public branch. That's just asking for garbage that noone should concern themselves with to accidentally get pushed up at the end of a long-ass day.
That seems naive. You don't know what's pointless for years, usually. Can I tell you how many times I've gone back to stale pull requests and topic branches to recover "How did I do this?" code?
> 2) I need to get them off of my local machine for disaster-recovery purposes.
That's called a "backup", and yes, data robustness is a big advantage of this workflow. You're acting like this is some kind of rare event. I push my local work to a branch (or three) on github every hour!
A corrolary is hardware independence, btw. Working off remote branches means I can also stand up a replacement development environment with a simple clone. (And the corrolary to that means that I can trivially document this such that other people can stand up development environments for my stuff, too!)
> It sounds like an overly complicated process compared to having a branch and rebasing onto the current branch when you finally go to make the change for real.
Not sure I understand the problem here? The rebase is the hard part. It doesn't help you to have a name for the code you're coming "from". If it collides it collides and you have to resolve it.
What I said about tags was just as short term memory "This commit right here worked on this date", stored in a way that (unless I delete or force-update the tag) I can't forget or pollute. Branches don't have that property. And again local branches don't have any advantages.
...Not that I am gonna follow that advice, of course. Same as I'm not gonna use git switch for a task git checkout does perfectly well.
If you later decide that the CLI is faster, go ahead. But first, people need to see visually how they can interact with the tree.
I like fork.dev, but most clients are pretty similar at this point.
I use Magit and doing things like "abort cherry-pick" is discoverable in the interface itself and uses the exact same shortcut as the other "abort X" operations. If I had to use the Git CLI, I'd have no idea where to start.
Similarly, I've made mistakes in interactive rebases where I deleted a commit that shouldn't have been deleted. If I recall correctly, the start of every rebase creates a snapshot that is accessible from the reflog, so this is a safe way to revert changes from a rebase gone wrong. Magit's UI for the reflog is exactly the same as the UI for the log, so I was not lost when I saw it for the first time. With the Git CLI, I'd likely have no clue what's going on.
It's really powerful because it gives you precisely that visual layout that shows you what's going on in the repository, and what you're doing right now.
The gripe I have is that unless you expose people to CLIs early on, they will just not learn how to use a CLI at all. Whenever something inevitably breaks badly due to GUIs abstracting away how git really works in favour of a nicer UX, they'll end up asking someone that know Git how to fix their mess. And then, it's too late - they already know how to be productive-ish with git and how to deliver something. They can't justify investing time into learning the CLI (especially if they're not that great with Powershell or UNIX shells) so they constantly keep leaning on a colleague instead of learning.
This is not an hypothetical scenario - this really happened regularly at a place I worked at. Innumerable internal training lessons on Git went wasted due to people forgetting everything immediately by using Fork instead of the shell, and then pestering a handful of senior devs. Once IT banned Fork people were forced to use the terminal more often, so they had to learn how to use git for good and actually retained that knowledge via muscle memory.
The adage I've learnt over the course of the years is that the majority of people will go to any length to avoid learning new stuff. It's mentally less tiring to either waste their time doing stuff in an unproductive way than learning new things. IMHO it's better to force people to learn stuff the "right way" early on than let them pick up bad habits and then having to correct them later.
It has generally worked better for me to use the same interface everyone else is using, even when that interface is awful, because that eases communication with the rest of the team. It also lets me take advantage of online troubleshooting resources, which all assume you are doing things the normal way.
Interactive tutorial with tree visualization that has helped co-workers: https://learngitbranching.js.org/
i don’t think i’ve typed out a full hash in … years? if i have i’ve used the short 8 character hash.
git rev-parse might be something useful to have a look at, especially when combined with aliases.
But I still have to find the short hash too, and then copy or re-type it… With a UI, I just… click click click done.
I used to be a CLI git guy but haven't used it in years now
1) all UIs are completely missing at least some of Git CLI's functionality (shoutout to git's most neglected feature, git notes)
2) all UIs have at least a couple git features so tucked away that you'll only find them if you know to look for them (git checkout -- path > temp_file is a common culprit here, but I've seen UIs that hide git ammend)
3) the average time for a UI-exclusive user to need my help for one of those two reasons was about a month.
to summarise: use the desktop apps now, but thou shalt need to learn the CLI.
—
when i’ve taught absolute development beginners how to use git and how to do PRs i show them both the CLI and GitHub desktop. not every single thing. but i at least show them add/commit/push and creating/checking out branches in the CLI.
why?
1) this CLI thing is what power users / experienced folks use. this is your long term goal.
2) oh look, the terminal is typing things out instead of clicking on buttons which have slightly different names (target audience has never seen a terminal)
3a) some things cannot be unfucked in a desktop app. i don’t have to explain what the CLI is to show them how to unfuck it. i might have to remind them. but it’s not totally alien to them. they’re only seeing the fix for the first time, not the fix and the CLI.
3b) they might feel more comfortable trying to use the CLI when they’ve already been shown it before. ideally in tandem with 3a — “hey i need to do this thing to unfuck it, could you sit with me while i go through to avoid fucking it even more”
4) maybe they go “screw it, i want the pain because i really want to be a magician at this”. it’s nice for them to have the option of the easier, simpler path when they’re having a bad day with it.
ill always suggest that absolute beginners use the desktop apps because it does reduce early fuck ups. and part of that involves showing them the desktop apps.
but i feel they need to be made aware the desktop apps are not the be end and end all. they can try the CLI a few times if they want. at some point, they will have to use it.
they also need to learn to fuck it up. making mistakes is how human beings really learn.
both making mistakes and demo-ing the CLI early, often and safely; rather than later and rarely; gets people to “magician” level faster in my experience.
essentially, you have more to learn buddy. keep working on it if you want to be one of the magicians in the team. if you don’t, that’s fine. but at some point you’ll need to deal with this CLI thing.
—
> people need to see visually how they can interact with the tree.
i’ve got a whole diagram thing i draw live showing them how everything is based on commits or a collection of commits, moving the commits around in front of them.
seems to be a better way to cover remotes, branches and eventually PRs than leaving them to work it out with some history visualisation which is usually a bit hard to read.
I was there. And at some point I wondered if I should learn git, darcs, or bazaar, to replace SVN or CVS. Or did I try mercurial too ?
I wonder if the "GitHub" effect has basically killed the need for a newcomer in the space of VCS. Maybe at some point, the yak is shaved enough ?
I am growing increasingly frustrated with various aspects of GitHub, and so I hope someday we all move past it too, but I don't think there's as simple of a path forward there.
It is its own footgun as well, but with git you can git init any directory you want and have a repo. Other than the learning curve of the not particularly well tuned CLI (and there are all sorts of graphical clients today and alternative CLI clients), it's very low barrier to entry to get something/anything in source control.
It's not just "larping as leet hackerz", there are real benefits to git over SVN. There are fewer barriers to entry for small teams and hobby devs, especially in a world with GitHub/GitLab/Sourcehut/and more, but also in the world where maybe a git repo never syncs with any other single machine or is hosted on the barest feature set SAMBA folder or is only ever using email-based PR flows.
git could be easier to teach. git could have a better out of the box CLI. That doesn't mean "git is overkill" especially from the point of view of "needing a whole central server setup just to store multiple versions of a file is overkill". Git is perhaps "underkill", it does the bare minimum as best it can in whatever environment you give it. It's intentionally dumb and stupid (hence its name, to be fair) and it's learning curve is as much because it is "too dumb" than because it "isn't intuitive". I've seen some "intuitive" UIs built on top of it. Another comment here remarked "git isn't a source control system, it's a low level toolkit for building your own" and that's not far from the truth and definitely not far from git's origins (and its name). That's a sort of "underkill". ("One day we'll finally build the right, intuitive high level API." That's basically how git was designed. You don't have to just take my word on that, you can search the old mailing lists for all sorts of interesting discussions and debates on "porcelain" options.)
Many years ago, SVN worked fine for me for single-user projects. I just made my own desktop be the server. But I wasn't publishing my code back then (it's not as if I would have have any effective way to tell people about it anyway). Now I have no idea how the equivalent of "pushing to origin" would have worked.
You can even do it on shared directory for a small team even it's not recommended if there is a lot of concurrent users.
No, but seriously, I wrote https://andrew-quinn.me/reposurgeon for a reason. While I actually see some big benefits to SVN over git for areas with large binary assets like game development, the tool is just so ancient these days that it's just easier for me to convert SVN repos to git repos and then use those to figure out what I actually need to do. It feels a lot like working with Laplace transforms, translating and un-translating between two not quite equal ways of measuring reality.
That's not even considering that the kinds of companies still using SVN in 2025 tend to have a lot of code to wade through. Serious selection effects in play there -- mostly for good, to be clear.
Hosting is available at least from Sourcehut and heptapod.host.
I'm running a private Heptapod instance (Gitlab fork with direct Mercurial support). It just works.
Sourceforge, Sourcehut, and GNU Savannah all support Mercurial.
I don't know if that's because the text UI is bad, or because it's simply difficult to explain with text what to do to manipulate a tree.
Manipulating complex trees via text is not easy, but the text UI is objectively bad:
git break-my-shit
git reflog
... output saying where you were before things broke
... grab the good commit sha
git reset --hard good_commit_sha_from_reflog
git unshit
Or git add --unshit -f ~HEAD^^
If you’re using git version <= 2.844."Uh oh, I tried to checkout a branch from remote by doing `git checkout origin/some-branch` instead of `git checkout some-branch` and made a couple source changes. Now I'm in detached head state. What is detached head ? I have to stash my revisions? Can I make a new branch with the same name or do I need to delete the origin/some-branch that I'm on?"
When you could be able to just revert the "operation" and check out the correct branch, that's amazing.
Every time I see `git reflog`, I see it as re-flog. It's possible that's even the reason I never remember the command, I subconsciously can't bring myself to think of it as "reference log". Instead, it's asking git to sell something cheaply, again.
It's like saving a textfile. Do you write a little message every time you save a file? No that's silly. Just move on.
(Although also/mainly in the comments if it's something I worry someone might accidentally change back later.)
Or you can just squash-merge your PRs and reap both benefits.
Do you write a little message about your day every time you go to sleep?
I actually don't, and maybe you don't, but plenty of people do.
I think of the Git revision log as much like that sort of diary, offering the same sorts of advantages. It's more organized than having a separate TODO list document; and it encourages you to describe what you've already done in a clear readable way, too. When you're trying to figure out how far to roll back, it may be useful to understand what you were thinking at the time of the commit. And if something turned out to be the wrong approach, it helps you do the post-mortem.
And, of course: if your unmerged, unpushed work is organized into separate changes that have separate (and labelled goals), and part of that work turns out to be good and part bad, it becomes vastly easier to preserve the good parts.
With that said, it obviously is not meaningless at a technical level because without the commit there is nothing to push or merge. On top of that, at a non-technical level it can be extremely helpful to record some plain-english prose to describe why you are changing something. If you find yourself doing that too often you need to narrow your definition of what constitutes a "change" and/or be more discerning about what you work on simultaneously.
Out of curiosity, if you do not use git, what do you use for version control and change-management?
Committing often is key. Precommit hooks (that take more than ~100ms) go against that.
Even things like "git add" will create objects stored in the .git folder.
It saved my work a couple of times.
"Gonna have a bad time?" I really wish things like this were explained in more detail, rather than with glib warnings that are unhelpful unless you already know what they mean.
Warnings about detaching the HEAD in git are so common that they're kind of assumed to be basic knowledge to a lot of people. Explaining why it's bad if you don't already know would take quite a while too.
I do wish git had some form of warning before you rewrite history that's been pushed somewhere. It should already have all the data to know that.
It really says something about the design and documentation of a tool when you need a (far more complex and energy-intensive) Artificial Intelligence to be able to use it without making too many mistakes.
Oh Shit, Git - https://news.ycombinator.com/item?id=31874308 - June 2022 (232 comments)
Oh Shit Git? - https://news.ycombinator.com/item?id=24173238 - Aug 2020 (156 comments)
Oh shit, git (2016) - https://news.ycombinator.com/item?id=19906972 - May 2019 (277 comments)
Oh shit, git: Getting myself out of bad situations - https://news.ycombinator.com/item?id=15951825 - Dec 2017 (509 comments)
Like, reset vs revert vs restore, using three similar starting synonyms for different operations.
Reset is particularly confusing because it sounds incredibly destructive, but if you do a soft 'git reset', it just moves the "changes to be committed" to be not staged for the commit.
Then, if you change a single flag (--hard) it is destructive, instead erasing all those changes from your disk.
And there's a reason nobody reads the docs, because they're laid out confusingly at first glance to an unfamiliar person.
If I go to git-scm.com, click docs, the first suggestion is the reference manual. The first guide is on "gitattributes" which gives no philosophy or context as to what it is even used for. Ok, maybe, I'll just check the complete list of git commands... and it starts talking about porcelain and plumbing. Nope, thats not what I need. Maybe try the link "git" under Setup and Config. There the description finally links to a useful "gittutorial" page.
The gittutorial even has some confusing or specific terminology that makes git seem hard. From the beginning of importing a new project "Assume you have a tarball project.tar.gz with your initial work"... why do we need to refer to tar at all, and it doesn't even do the credit of explaining the tar xzf command or what that tarball is. It could easily say 'assume you have a directory', which is the more common case and be 200% more simple.
A nicer way is merge master into your branch, with the rebase option (you can set that option as the default). This will put your changes on top of the master changes that happened during populating your own branch. There you solve any conflicts and those usually immediately show you what happened in the meantime, making it easier to do so. The latest greatest now sits in your branch.
Then as a plus, you can retest that merge and if necessary, fix the merge.
Optionally you can do a pull request for reviewing. The diff the reviewers see is conflict-less and makes sense, has only your changes.
Then simply merge to master, which should be trivial if you don't wait for long.
The same problem GP was trying to avoid is created here, the merge conflict resolution being on the merge commit.
git merge origin/master
git reset origin/master
git commit -am "squash" # might need some extra fixup if your branch has added files
No need to make a temp branch. I know there's probably a more efficient way of doing this, but this is what's stuck in my head.Fortunately, I don't have to use git. So I just store work-in-progress as time-stamped files. Storage is cheap and plentiful. Can always diff, cherry pick, etc without confusing myself.
Has to be easier to understand that then all the arbitrary git commands.
(There is a similar sounding joke about category theory, "A monad is just a monoid in the category of endofunctors" but this sentence has a mathematical meaning.)
I can see how it would be a much bigger learning curve if people come straight to git, but it's still hard for me to understand where the blocker is that so many people complain about using it...
The built in way (filter-branch) pops up a warning, with a long delay, saying you should hit Control+C and go download a third party python script called filter-repo...
I take the more realistic perspective: until git makes it impossible to commit something that shouldn't have been, like a secret, then deleting a file from history is a fundamental requirement of git.
Think of it: one person who cares about UX decades ago could make git 10 times more sane for milions of devs.
Git's CLI isn't elegant, but it really isn't that big of a deal if you understand the basics of what a commit is, what a branch is etc.
I struggle to understand why so many devs decide to treat it like mysterious arcane sorcery instead of just spending the needed time on learning how it works.
The same can be said about regexes.
Regexes and git are probably the two tools which I have benefitted the most from learning compared to how little time I've spend on learning them - and I wouldn't even consider myself an expert on either.
Yes, that's what people mean when they say that git is hard. Instead of presenting you with an interface expressed in terms of the domain you intend to work in, whose commands represent the tasks you intend to perform, git dumps its guts all over the place and requires each user to re-implement the interface between "what you want to do" and "how git is built" inside their own brains instead. Once you have written git's missing user interface in your brain, you are fine; but that's a lot of work which is not necessary with other version-control systems.
For example: you have bazilion ways to achieve the same thing, all of them having its own quirks/advantages?
It is just poorly designed, that's it, lol.
I like to joke that if somebody else invented Git, then it'd be 10% less powerful, but 10 times more user-friendly
It's like complaining about languages ("English is hard to spell and doesn't have consistent pronunciation" etc.), they're constantly changing and that kind of thing is going to happen eventually...
See also: Docker. Probably lots of others.
The rest are good though.
This is how the reflog works. Whatever you do, you can get back to a previous branch state and restore the work from the data store.
But git can't help you if you don't commit. So just commit. Commit all the time. If you think it's too much overhead and you always forget to commit, fix your tools. If you're writing code all day you should be committing at a minimum every hour, in general.
Useful in case someone force-pushes and no one has the good ref locally.
https://wizardzines.com/zines/oh-shit-git/
Perhaps not and the authors just named it the same because it rolls off the tongue nicely.
Any, and I mean any "in case of a Git problem, just do this" recipe is wrong, often in very subtle ways. So, my advice: in case of a Git problem, contact the help channel provided by the organization hosting your Git repository. They'll help you out! And if it's your personal-I-am-truly-the-only-human-using-this repository? Just recreate it, and save yourself the pain.
Source: I'm part of the team behind the #githelp channel in many $DAYJOBs, and we know how hard things are. You committed an unencrypted password file, or worse, your entire 'secret' MP4 collection to our monorepo? Sure, just let us know! Pushed your experimental branch to master/main/head/whatever? We'll fix it!
Just don't ever, for whatever reason, run that-chain-of-commands you found on the Internet, without understanding what they do! In most cases, your initial mistake can be undone pretty quickly (despite requiring nonstandard tooling), but once you're three levels deep and four days later, not so much...
Sites like this are a great aid to remembering how to deal with certain situations. And yes, I understand what the commands do, but that doesn't mean I always could, or always want to, put together the series of steps from scratch.
And also, we self-host our own gitea hosting because we're not getting sucked down by yet another hosting debacle (old enough to have suffered under sourceforge, and don't plan on getting in the same situation again). For git hosting just as much as everything else on line, if you're not paying for it, you're not the customer.
Yeah, lovely trope, but I'm literally talking about organizations hosting their Git repos on a file share here.
And, by the time a '#githelp team' is formed, it's to address patterns to which there are known solutions.
One of the many problems with Git, is that these solutions depend very, very much on the structure of the repo and the common practices of its users.
So, instead of executing random commands from the Internet, just ask. Please! Or, if there's truly nobody going to be around, give in and recreate the repo. You'll save yourself so much pain in the long run...
I'm the resident git expert, but not by choice. There's more that I don't know than that I do. It's not uncommon that I need to use internet recipes to un-wedge someone's clone.
> Or, if there's truly nobody going to be around, give in and recreate the repo. You'll save yourself so much pain in the long run...
This is insane. There are a dozen other people using the remote, not to mention a whole CI/CD build configuration.
I applaud you for your honesty, but... Really?
Although to your point folks would be better served carefully reading the docs / git book than googling a specific solution to their specific error code.
Really?
It's gender neutral btw.
That's actually how it was originally, because in Old English "man" just meant a gender-neutral "person."
Gendered versions were "wer" and "wif", so you could have a "wer-man" and a "wif-man", the latter changing pronunciation to become "woman". I suppose this also means that there are both "werewolves" and "wifwolves".
Oh no, that poor soul...