Live data from Hacker News

Oh Shit, Git?

ohshitgit.com

121–130 of 275 posts

Re: Oh Shit, Git?

#121
post #3

Some changes I would make: 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 th…

Rewriting these for jj users. I'm prefering long option names and full command names for clarity here, but all the commands have shortened aliases and all the option names have single-letter alternatives. `@` means "the current revision", `x+` means "the revision just after `x`", `x-` means "the revision just before `x`".

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

Re: Oh Shit, Git?

#122
post #3

Some changes I would make: 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 th…

millennial boomer here where is the gen z cheat sheet for this git switch thing that i keep hearing about

Re: Oh Shit, Git?

#123

My hot take is that Git isn't nearly as hard as the endless blogs pretend.

I'm happy I didn't have to scroll too far to see this. 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 t…

>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.

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

Re: Oh Shit, Git?

#124

This will feel very weird in April 2025, when we celebrate the 20th anniversary of git. 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 ?

SVN has always worked for me. You don’t have to “teach” people SVN because it’s intuitive and works just fine for the 99% case. I wish we would all stop larping as 1337 hackerz and just admit that git is overkill for the vast majority of people.

I agree with your sentiment. I was kind of "forced" to use (and eventually fully migrate to) git because the IDE integration to SVN became more quirky every year. Instead, git is already integrated in IDEs these days.

Re: Oh Shit, Git?

#125

This will feel very weird in April 2025, when we celebrate the 20th anniversary of git. 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 ?

SVN has always worked for me. You don’t have to “teach” people SVN because it’s intuitive and works just fine for the 99% case. I wish we would all stop larping as 1337 hackerz and just admit that git is overkill for the vast majority of people.

Starting a new repo in SVN is find a server somewhere, if doesn't have SVN install SVN, if it does have SVN deal with whatever politics runs its trunk to find space/define a branch structure for you, and so forth.

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.)

Re: Oh Shit, Git?

#126

My hot take is that Git isn't nearly as hard as the endless blogs pretend.

I'm happy I didn't have to scroll too far to see this. 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 t…

> it really isn't that big of a deal if you understand the basics of what a commit is, what a branch is etc.

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.

Re: Oh Shit, Git?

#127

Lately I've been asked to avoid merge-commits. They pollute the logs? If my push is blocked I am too far behind I create a new temp branch of master and do a "merge --squash" to it and then a "reset --hard" from temp branch back to my original branch. Heck sometimes I rather keep my changes in patches to void does darn merge CONFLICTS...specially when rebasing.

I think that people that think merge commits "pollute the logs" are missing key git features such as `--first-parent`. Git is natively a graph. It gets a lot of powers from that. If you don't want to see all the details of the "subway diagram", add `--first-parent` as a default and focus on the higher level. Merge commits help avoid later conflicts by saving how earlier conflicts were solved. Three-way merging in general and many of git's more complex merging strategies all work better if you save the merge commits. Rebasing throws that baby of information out with the bath water. (It's also useful information to have as a developer needing to archeology dive for how a regression happened. With a merge commit you can see the fingerprints of a bad merge or a mistake that wasn't caught in an ugly merge. With a rebase or squash that information is gone, you have no idea where to find the bad or ugly merges, that data is swept under the rug.)

Re: Oh Shit, Git?

#128
Love that the very first thing mentions reflog, arguably the most confusing and complicated git feature.

The rest are good though.

Re: Oh Shit, Git?

#129

Earlier quoted context omitted.

The disconnect between git's beautiful internal model of blobs, a tree of commits, and pointers to commits, and the command line interface is so wild. All of these recipes are unintuitive even if you have a firm grasp of git's model; you also need to know the quirks of the commands! To just look at the first one... wouldn't it be more intuitive for the command line interface to be: # this command exists already; $ gi…

Are there alternative git command lines that keep the beautiful internals, but implement a more elegant and intuitive set of commands to manage it?

Another vote for jujutsu. No one else needs to know you're using it. You can think of it as just a different CLI for git (although you shouldn't mix them). I used to use third-party interfaces like lazygit, but I don't need them anymore because jujutsu _just makes sense_.

Re: Oh Shit, Git?

#130
post #118
post #3

Some changes I would make: 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 th…

Could you motivate why you suggest these? Why is `switch` better than `checkout`? And why not use `reset --hard`?

Not comment OP, but checkout has two very different uses merged into one: restoring files and switching branches. To not break compatibility, git has now switch and restore commands that make commands more readable and understandable.

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.

Post reply on HN