Hacker News new | ask | show | jobs
by litenboll 225 days ago
I think what people usually mean is "scary" or "it's easy to mess up". Git is very easy to use until you mess up, then it can become complicated, and certain actions may have devastating consequences.

Two examples from recent memory:

Someone merged the develop branch into their branch, then changed their mind and reverted the merge commit specifically (i.e. reversing all the incoming changes), then somehow merged all of this into the develop branch, undoing weeks of work without noticing. I had to go in and revert the revert to undo the mistake. Yes they messed up, but these things happen with enough people and time.

Another very interesting issue that happened to a less technical person on the team was that their git UI somehow opened the terminal in the wrong folder. They then tried to run some command which made git suggest to run 'git init', creating another git repo in that wrong location. Fast forward some days and we had an issue where people had to clean their repos, so I was in a call with the person helping them run the clean command. The UI opened the wrong location again, I helped them put in the command and it started cleaning. The problem was that this git repo was essentially at the top level on their disk, and since was a fresh repo every single file was considered a new file so it tried to delete EVERYTHING on their disk. This was of course mostly my fault for not running git status before the clean command, but this potential scenario was definitely not on my mind.

1 comments

I mean. How can it be scary when you have git reflog.
The reflog doesn't capture everything. jj's oplog does.

An example of something that the reflog isn't going to capture is a git reset --hard losing your unstaged changes, whereas the equivalent flow and commands in jj would allow you to get those contents back.

The thing to keep in mind is that Git doesn't version the file system, it versions the index. This is because a file system guy like Torvalds knows that the file system is a shared resource and no program should think it can control its state. Therefore a Git repository doesn't consists out of all the files below a directory, it consists out of everything in the index.

Git does version everything that is in the repository and all these states occur in the reflog.

> The thing to keep in mind is that Git doesn't version the file system, it versions the index.

Yes. I think that this difference is what introduces a lot of friction, both in the model, and how people use it. The divergence between the files that exist on disk inside your working copy and what's actually tracked means lots of opportunities for friction that go away once you decide that it should. That doesn't mean things are perfect, for example, by default jj only snapshots the filesystem when you run a `jj` command, so you can still lose changes from in between those, you need to enable Watchman to get truly full logging here.

> all these states occur in the reflog.

Well, let's go back to the documentation for reflog:

> Reference logs, or "reflogs", record when the tips of branches and other references were updated in the local repository.

It only tracks changes to refs. That is, the states that refs have been in. So, one big example is detatched HEADs: any changes you make to those, which still are contents of the repository, are not tracked in the reflog.

Even for refs, there's differences: the reflog says "ref was in state x and changed to state y" without any more details. jj's oplog keeps track of not only the state change, but the reason why: "rebased commit <sha> with these args: jj rebase -r <sha> -d trunk"

The reflog only tracks individual refs. Say we rebase multiple commits. The reflog still just says "the head of this branch was in state x and changed to state y" but the oplog says "a rebase happened, it affected all of these commits refs in these ways," that is, it's just inherently more rich in what it tracks, and does it across all relative commits, not only the refs.

This doesn't mean the reflog is bad! It's just a very specific thing. Git could have an operation log too, it's just a different feature.

> So, one big example is detatched HEADs: any changes you make to those, which still are contents of the repository, are not tracked in the reflog.

    $ git checkout HEAD
    $ git commit --allow-empty -m "_"
    $ git checkout master
    $ git reflog
    a91 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: checkout: moving from b94 to master
    b94 HEAD@{1}: commit: _
    28d (origin/feature, feature) HEAD@{2}: checkout: moving from feature to @
> Even for refs, there's differences: the reflog says "ref was in state x and changed to state y" without any more details. jj's oplog keeps track of not only the state change, but the reason why: "rebased commit <sha> with these args: jj rebase -r <sha> -d trunk"

> The reflog only tracks individual refs. Say we rebase multiple commits. The reflog still just says "the head of this branch was in state x and changed to state y" but the oplog says "a rebase happened, it affected all of these commits refs in these ways," that is, it's just inherently more rich in what it tracks, and does it across all relative commits, not only the refs.

    68e HEAD@{15}: rebase (finish): returning to refs/heads/feature
    68e HEAD@{16}: rebase (pick): message #6
    7ff HEAD@{17}: rebase (pick): message #5
    797 HEAD@{18}: rebase (pick): message #4
    776 HEAD@{19}: rebase (pick): message #3
    c7d HEAD@{20}: rebase (pick): message #2
    f10 HEAD@{21}: rebase (pick): message #1
    c0d HEAD@{22}: rebase (start): checkout @~6

    a7c HEAD@{100}: rebase (reword): message ...
    3b1 HEAD@{229}: rebase (reset): '3b1' message ...
    4a4 HEAD@{270}: rebase (continue): message ...
Oh yeah I forgot HEAD Is a ref, whoops. Duh! (My git is getting rusty at this point...)

jj still ends up keeping information in here that the reflog doesnt, but you're right that these aren't the strongest points.

That makes sense