8 ms·
Reading through this and then thinking about rebases in particular.... I think whoever comes up with a good mechanical explanation of rebasing deserves a prize.
by rtpg 3y ago
Reading through this and then thinking about rebases in particular.... I think whoever comes up with a good mechanical explanation of rebasing deserves a prize. I just imagine it as "it figures out diffs and then tries to apply them over at another place" but this runs up against reality way too often.
- juped 3y agoHow does this "run up against reality", it is the reality, full stop, not even eliding tricky details. Whatever made you say that is the part of you that's confused here.
- krupan 3y agoIt's not the reality. It is a 3-way merge of each commit you are rebasing, not just applying diffs. Except sometimes when I'm resolving conflicts git mergetool doesn't seem to supply 3 files to kdiff3 (just two) which really really bothers me. Never saw that with Mercurial
- juped 3y agoIt's the reality, it's just applying diffs. The OP's blog actually has an earlier post about how applying diffs uses a 3-way merge; before ort and its more versatile API which can handle just applying diffs, rebase literally used apply machinery.
- krupan 3y agoSorry, when I think of applying diffs I think of using the patch command that literally takes a set of files and a diff and applies the diff to the files. patch doesn't know any history and doesn't do 3-way merges. In my mind a 3-way merge is different than just "applying diffs" I'll look for her post about rebase, it sounds interesting, thanks!
- juped 3y agodiff(old, new) is sort of a degenerate case of diff3(left, base, right) where left = base; if your patch came _from_ git in some capacity it can identify base and doesn't need to fall back
- krupan 3y agopatch is a program that operates on diffs, which are also sometimes called patches, confusingly. Your reply seems to be conflating patch the program with diffs (AKA, patches)
- mr_mitm 3y agoI imagine it as separating a branch from the rest of the tree and attaching it to a new base commit ("rebase"). Naturally you need to apply all diffs (interpreting commits as diffs here) from the original branch to the new base commit. So you re-based it.
- krupan 3y agoDoes this explanation help? http://bryan-murdock.blogspot.com/2022/12/git-rebase-explained.html http://bryan-murdock.blogspot.com/2022/12/git-rebase-explain... Rebase is really a merge (actually one merge per commit you are rebasing). At least it should be. With mercurial it really seems to be. With git I'm not so sure because it feels like it's always worse at resolving conflicts than mercurial. I haven't tested it thoroughly or looked at the implementations
- nerdponx 3y agoInteresting that this article omits any mention of "cherry-pick".
- kelnos 3y agoI don't think that's a very good explanation. It only considers one possible use of rebase, to resync a feature/topic branch with a main branch that has diverged since the branch was created. Another common use case for rebase is to clean up an already-linear history. And even then, when using rebase to "resync" different branches, I don't think it's accurate to characterize it as a merge at all. It's a hard reset plus a series of cherry-picks. (As an aside, this is why rebase can be much more annoying than a merge! Merging a branch onto another is usually quick and easy. Git's merge algorithms usually do a decent job of figuring out how to do a merge without conflicts. And if there are conflicts, you only have to resolve them once. If instead you rebase, you may have to resolve the same (or similar) conflicts over and over and over, once for each cherry-pick. And there might be conflicts that wouldn't have even occurred with a simple merge. Git's rerere mechanism does automate some of it, sometimes, though.)
- krupan 3y agoA couple things. That blog post shows the case of rebasing a single commit and so yes, it doesn't talk about interactive rebase that lets you reorder and edit commits, and it doesn't talk about rebasing multiple commits. In the case of multiple commits, it has to perform a merge operation for each of those commits, that's why you end up seeing the same merge conflicts over and over. For interactive rebase, there are so many scenarios there that it would probably take a few posts to explore them all.
- samus 3y agoI recommend striving to understand what `git cherry-pick` does, since that's equivalent to rebasing a single commit without doing anything else. That parts is where you get rebase conflicts from. Everything else `git rebase` does is a combination of `git amend` and `git squash`.
- rtpg 3y agoThat's a very good point. Thanks for that!
- nerdponx 3y agoHere's some Python pseudocode of the mental model that works well enough most of the time? def rebase(base, curr=HEAD): common_ancestor = git_merge_base(base, curr) git_checkout(common_ancestor) for commit in commit_range(common_ancestor, curr): git_cherry_pick(commit) Does that help?