6 ms·
> Rewriting history with rebase is a destructive operation. It's not, because Git history is immutable [0], you can't change it. But I understand that from the
by darekkay 3y ago
> Rewriting history with rebase is a destructive operation.
It's not, because Git history is immutable [0], you can't change it. But I understand that from the user perspective it appears to change, and the consequences for public history "changes" have to be known to prevent any troubles.
[0] https://darekkay.com/blog/git-rewriting-history/ https://darekkay.com/blog/git-rewriting-history/
- epcoa 3y ago> It's not, because Git history is immutable [0], you can't change it. > It is by design impossible to modify or delete an existing commit with regular Git commands. These are both just straight up incorrect. Make the commit unreachable from all regular branches (this can be as simple as a reset or rebase - and at this point is effectively rewriting history), then gc. Oh, ah you say, there’s a reflog. But that can be pruned/expired with the very same regular reflog command you refer to in your post (or just change the unreachable expiry from 30 days to now). At that point the commit is truly unreachable and a gc will make it go away forever. FYI the commands git reflog expire --expire=now --all && git gc --prune=now should do the trick about truly deleting commit objects for good. Also the filter commands allow rewriting history. This makes a difference because your wording implies that there is some inherent structural invariant that makes git history immutable - and there certainly isn’t, there’s just some default policy for how otherwise unreachable objects are recoverable. Also I think when most people say (correctly [0]) that git history is mutable it is that by default it is easy to rewrite the history of any branch and basically manipulate the commit graph in any way, and all can be done with the standard command line tools. Bringing in the reflog is mostly irrelevant to the concept of history rewriting. > But I understand that from the user perspective it appears to change If you force push to a shared repo, there's no "perspective" about it - the history has changed, somebody else may basically get a completely unrelated graph to what they have in their own repo. Bottom line: The person you're replying to is correct, rebase is a fundamentally destructive operation, because while the objects in git are immutable the references are not and that's all that matters - because a commit without a reference might as well not exist, it's not a history, it's just a commit. Starting with rebase you can prove to yourself that you can make the repo dispose of commit, tree and blob objects forever. I see the distinction that you are trying to make but I don't see why it is either pedagogically or practically a useful one. [0] https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History (no scare quotes needed)
- darekkay 3y agoThanks for your input. You're right, my statement is not fully correct and I will also update my post. What I mean with "regular" are commands like "rebase" - just running "git rebase" is not destructive in a way that your previous changes are truly gone (by default). That's actually a pretty important thing to know both pedagogically and practically, as it makes it trivial to undo a rebase. If rebase was actually "destructive", you couldn't do it. You've stated a lot of ways to delete commits that I don't see as "regular" (gc, changing default expire date, filter, reflog, ...). There are even more plumbing commands to delete commits. But yes, I should have explained what I mean with "regular" and also make my point less absolute. > If you force push to a shared repo, there's no "perspective" about it - the history has changed. It depends on what "history" and "changing" means to you. If it's the entire Git graph, then every commit changes the history (which it does). What I mean by change in this context is that I can take a graph and alter the existing commits (change order, move, change the content, etc.), and that's not what happens with a rebase for example. I should have clarified this as well. It comes down to the "branches are just pointers" discussion, so for me, moving a branch does not "change" the history (= the commit graph). But I also understand that from a different perspective - viewing the branch as the pointer + the commits it reaches - the history actually changes (but not in the way I've meant it). It's important to state which of those one is talking about.
- epcoa 3y ago> You've stated a lot of ways to delete commits that I don't see as "regular" (gc, changing default expire date, filter, reflog, ...). If reflog is not regular then by your own set of constraints you’ve “deleted” a commit the moment it’s unreachable from any regular branch or stash - which is what most people think when they say “deleted.” Deleting a line of code or a paragraph of text is still deleting even if I can undo it through the very system we’re discussing. I don’t actually think gc is germane but it was to drive home the point that there’s nothing like cryptographic signatures or something that make objects undisposable. Further a force push after rebase is destructive because there is no reflog on a remote bare repo. The corollary is that force pushing deletes commits that are impossible to recover with any “regular” git command. > That's actually a pretty important thing to know both pedagogically and practically, as it makes it trivial to undo a rebase. Then just simply say things can be undone with the reflog. > What I mean by change in this context is that I can take a graph and alter the existing commits (change order, move, change the content, etc.), and that's not what happens with a rebase for example. > It's important to state which of those one is talking about. Why? > But I also understand that from a different perspective - viewing the branch as the pointer + the commits it reaches I don’t understand what is “different” about this perspective, a branch is literally the pointer. A commit object is not a branch. > moving a branch does not "change" the history (= the commit graph). It will point to an entirely new commit graph. This is a change. The commit graph you refer to may very well be orphaned (ie deleted) at this point.