Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

My main issue with Git, other than the terrible UX of the CLI, is just how common it is for one to want to rewrite the commit history - an operation for which there's no version control.

You better get it right, or otherwise you get to nuke the whole repository.



Perhaps this is a byproduct of the UI (which I totally agree is bad), but this is not true.

`git reflog` contains a full history of all refs you’ve been on in chronological order. Unless you explicitly delete them, dangling refs are not cleaned up immediately. If you rewrite history and realise you made a mistake, you can likely recover by simply resetting the mutated branch to something from the reflog, even days or weeks afterwards (the default reflog retention is 30 days).


You learn something every day!


Another super simple technique is to create a branch where you start to go back to if you need to; ie if you are rebasing `foo`, start by running `git branch foo-back` and you can always reset back there if needed.


Since I often play with razors by rebasing, resetting, cherry picking, etc locally - I created a `git tmp` alias so I can play without fear of needing to go reflog diving again.

The `tmp` command creates a commit of all changes, branches it, then rolls back the commit.

[1] https://github.com/flurdy/dotfiles/blob/master/.config/fish/...


This temp branch (or even `git tag my_orig_branch`) approach is usually a better on-ramp than the reflog. It's still too easy to misread the line in the reflog of a prior HEAD change and go to the wrong commit, whereas the tmp branch is foolproof (and fatigue-proof).


There absolutely is version control for rewriting commit history, no fancy tools needed.

Start another branch at the point where you want to rewrite history; don't switch to it: `git branch original-history-branch`.

Now `git rebase` your branch to your heart's content. This branch will have the new, rewritten history.

The original-history-branch still has your old history, refers to your old commits and prevents them from being garbage-collected, just in case you'd like to reset your target branch to that state.


That’s like saying the operating system has version control built in, no fancy tools needed, because you can `cp my-code.c original-my-code.c`, edit `my-code.c`, and have `original-my-code.c` just in case you’d like to reset your code to the old version.

That is to say - sure, it can work, but automated history tracking is far superior.

Though, git does at least have reflog, so if you accidentally delete or overwrite a branch, you should be able to get it back. That’s far better than the equivalent situation with files on a filesystem. But it’s still not real history tracking.


This is true, and this is entirely the UI / workflow problem.

Git keeps a version for you while you are doing a rebase, so you can say `git rebase --abort` and get back to the preserved state. But it does not keep a log of these, and, more importantly, does not ask you whether you are glad with the end result: you cannot --abort right after a rebase completed without conflicts. One would say that you should explicitly do something like `git rebase commit` (or `git merge commit`) after you have reviewed the result.


And that original-history-branch is either dropped or lives on happy ever after, polluting a crowded namespace. Or it's the base of some parallel development and then that's merged and you end up with every commit twice in the history. I guess the github model of forks and PRs might help, but that's not git, it's git with an added workaround.

Another approach (which might not be git anymore, but close enough to talk about in git nomenclature) might be some kind of facade layer for the history where you fix wrong comments, bundle up old commits to linear groups and so on. A commit hash would still reference a code state, but the repository state (code and its revised history presentation) would be something like "g123abc as seen by g345fed", usually "g123abc as seen by branch/HEAD", perhaps width some clever defaults like "head of whatever branch has the most recent commit on top of g123abc"


You might be interested in my project git-branchless https://github.com/arxanas/git-branchless or the Git-compatible Jujutsu SCM https://github.com/martinvonz/jj, both of which have version control for commit history via an operation log. Both feature sensible `undo` commands.


The old commits with old comments are still there for a while and 'git reset --hard' can be used to get back to the old way. After a rebase there is a ref named ORIG_HEAD and a log in .git/logs/refs/heads (though I didn't really know that, I just went looking through my .git folder).

If you do a big force push on a remote repository you could keep the old stuff in a tag or a branch.


which is why I love Mercurial as it's immutable by default. You have to try really hard to mess up your repository.


Which is why I don't love Mercurial, because once you mess up your repo, it's messed up forever.

IMO "easy to break but easy to fix" is better than "hard to break but impossible to fix", and there ain't no such thing as "hard to break" after enough time passes.


How do you mess up an immutable repository?


Accidentally commit a huge video to a code repo (stupid as it sounds, this actually happened at a past employer). Make commits with unreadable messages, huge-ass commits with tens of logically different changes, split a single logical feature over several commits, etc.


Even when you rewrite the commit history, the old objects are kept for a while (or until you forcibly expire them).

You can find the "old" commits using "git reflog".

I've fixed a lot of botched rebases with that :)


Big issue is parent commit hash included in the commit hash. You have to rehash all commits following a history change.


I wouldn't call that an issue, more like an indispensable core feature! The fact that git bled the content-addressable hash through to the front of the UI is an underappreciated stroke of genius as far as I'm concerned.

It takes so much of the guess-work out of build tools, CI, etc.


Doesn’t git reflog answer that?


It's local to a single repository, can't be pushed anywhere, and is collected periodically by git gc.


I don’t see why OP would need any of that to undo an history rewrite they messed up.


And as a black-eyed veteran of DCS and (oh, thank god, SVN) and P4 and other stuff, and migrations from one to another and . . . often stuff that wasn't actually source control . . .

I say stuff it!




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: