Also, bisect is definitely not common, and the vast majority of my colleagues wouldn’t know it exists; I’d place it into the look-it-up-if-needed category.
Also, bisect is definitely not common, and the vast majority of my colleagues wouldn’t know it exists; I’d place it into the look-it-up-if-needed category.
Innocent typo but for anyone else reading, it’s “rerere”.
No, you have two commits. Git commits are snapshots, not diffs. Git's data model is simple. The fact that people do not bother trying to understand it is the root of the problem.
But yeah, after that initial push, it's just merges from there on out.
But you get rid of those ugly merges back and forth and unviewable histories.. Not sure why not more people care, I guess it is a little OCD I do that for my stuff.. however the 20-50+ user projects where everyone, often multiple times merges develop or even other branches in.. really unusable history right away, lets not talk about any point later. Git has derailed to a mere backup system where you can jump back, but understanding changes later becomes impossible :(
What people also rarely know: A linear history is without lies, but one can sneak additional changes into a merge commit that was in neither branch quite easy - I hate that!
I’ve had experiences where I’m trying to rebase a branch and it keeps flagging my most recent changes in the rebase when the intention is that I want all previous changes applied then as a final step show me a conflict if applicable, don’t show me one when it’s not the “final” step.
Admittedly maybe I’m doing it wrong.
I also don’t like how rebasing “main” onto my branch actually seemingly takes my branch and rebases it onto “main”? Maybe that’s a fault in my IDE not entirely sure
Not quite. That would mean that my old base is REPLACED by something else, right?
Instead rebase means take some other branch then put all the changes in the current branch on top of it, keeping everything in the current branch but just adding them on top of something else, right?
It grokked with me when in my IDE (WebStorm) I saw the menu-option allowing me to choose another branch and perform "Check Out and Rebase on top of the current branch". So you don't just "rebase a branch", you combine two branches. And when you combine two things here the order matters, and it is easy to confuse the order.
Similarly if you merge two branches, which one overrides? The left or the right operand? It is easy to get confused. Maybe I am. It is not my fault.
Every rebase really is at least three branches: what you're merging into, where you started, and where you are now. And God help you if somebody rewrote history on any of those.
The fact that all of these have terrible names makes it so much worse.
This makes bisecting a lot easier too.
Most people don't care about most stuff, it's pretty normal.
But here specifically: Most developers don't read code, nor documentation, and essentially no one reads commit messages. VCS is a WOLM - write-only linear memory - to most developers. That's probably also why most people don't care to write any kind of reasonable commit message - the software requires them to input something, so something is input - and also do not care about unreadable (and also unusable) VCS histories. They're never looking at it, it's only written. Hence it's meaningless for them if it is extremely difficult to trace changes or hard to bisect, they don't even attempt such things. There's a reason the history browsers in all the online tools and IDEs effin suck, it's because on average nobody uses history.
I know, I know, this gets across very elitistically, but it's just how most people do their jobs. They get bugged to do a thing, so they sort of do the thing in order to not be bugged any more about it. I'm pretty sure that caring for these things is some kind of OCD like you say, i.e. a mental disorder.
IMO merge is almost never what you actually want, unless you've been working separately for a long period of time (and generally you should not being doing that because it leads to surprising conflicts / regressions at merge time).
Let's suppose the next thing I do is add something to the bottom of my 5 branches. I dont switch to the branch, I stay on bl-dev and add a commit to bl-dev. Then I type "git rebase --update-refs -i HEAD~7" and move the commit up in the stack to the correct location and again all 6 branches update.
"git rebase --update-refs -i" also gains the ability to change which commit any branch points to.
I don't actually type "--update-refs", it's a gitconfig.
When you merge 17 changes from foo-feature into master, master has only a single commit. You cannot bisect master to determine which of the 17 broke master.
The 17 commits are there, but only in their original form, based on some old commit. Those 17 original commits are not equal to the single merged commit. The single merge could have a bad merge.
If there is going to be a bad merge, it's better to have a bad merge in one of 17 commits being individually rebased, than to have a bad merge in a single merge bomb that conflates 17 commits.
Your little branch of the original 17 commits should be purely a private object; it does not belong in the upstream. It's just a historic accident that your work was originally based on some three-week old random commit that happened to be latest at the time when you started. There is no need for that to be published. Your job is to make sure your code is based on the latest commit and promote it to the branch, as a sequence of individual changes (which all build and pass unit tests, etc).
I've literally not typed "git merge" since 2010, and around that time I learned how not to have Git perpetrate unwanted merges on me by learning never to type "git pull". "git pull" can be configured to be "git pull --rebase", but you will forget. I trained myself to do "git fetch", then "git rebase".
In all my last three jobs, the review tool Gerrit was used. Gerrit is based on cherry picking, which is rebase. Commits are submitted in their original form (not necessarily rebased to the target branch, but indicating which branch they are for). When approved, they are submitted and that means cherry pick. Maybe Gerrit can merge; I've never seen it used that way. Gerit has rebase right in the UI. You can take a commit and rebase it to its logical parent (latest patch set of an apparent parent with which it had been submitted together), or to the current head of the branch.
You start with a "main" rail of coats. Each coat is given a number, indicating what order it is in.
You start adding coats to a new, empty, rail, using the next number. When you are done collecting coats on this new rail, you want to move your coats onto the original rail.
In the time it has taken you to collect the coats onto your rail, someone else has already added coats from their new rail to the end of the "main" rail, and they used the same base number that you have - which means you cannot just add the coats from your rail onto the main rail, else the numbering would be broken - we call this a conflict. (NB: There is a magic guardian of the rails that means this just cannot happen, which is a plot device that is just to make this metaphor work so don't question it, it's just a metaphor.)
To resolve the conflict you have the following "rebase" options:
- Slide all of the coats on the main rail up to make room for yours, and update all of the numbers on your coats, using the new number from the last coat as the base number for your rail's sequence. This ensures that everything on the main rail is "before" your rail. This is the equivalent of a rebase. After this, you can then put your coats on the end of the main rail without conflict.
- Then there is the option to take a copy of the main rail onto the front of your rail, and organising the coats one-by-one (much like in the above), placing your coat(s) in between some of the new coats on the main rail, then forcibly replacing the main rail with your updated rail. This last one is just as drastic in reality as it sounds in this metaphor. We call this the "interactive rebase" and it is rewriting history for anyone who has used the main rail before.
- Finally we have a merge which means adding one big magic coat at the end that takes the coats from both rails and combines them in a singularity, with the new base number being Hawking's radiation or something, I dunno. The metaphor is no good for merges.
(Truth be told: the entire metaphor started in my head some years ago with just the visualisation of that distinct coat rail sweep noise to squish the garments on the rail to onside to fit what our main protagonist is holding onto the rail, the rest I just back-filled over time)
Many new users of git don't have the luxury of learning how to use local-only git with no remote.
Now rebase is a farm implement: a mechanized cherry picker. Cherry picking should be taught first, and then rebase explained in terms of being a multi-cherry-pick operation.
Before teaching cherry picking, you have to teach that Git is based on snapshots and not deltas. Git cherry-pick is part of tooling that is inside Git, but external to its snapshot-based storage model. When you cherry pick some commit into your current branch, the tool finds the common ancestor between your branch and that commit. It then does a three-way diff using the files in the cherry-picked snasphot, your own branch snapshot and the common ancestor-snapshot. The three-way diff operations produce a merged version that becomes a new commit: another snapshot.
If I ran a class on Git, we would spend part of a lecture doing manual merges with the diff3 utility: I would have the students take some ancestor file and make a "my" and "yours" with different changes, and merge these with diff3. We would go through conflict markers and all that.
Old time hackers who used other version control systems before Git knew all this stuff already. The first time I encountered conflicts, I already knew how to resolve them. Just a few git concepts were new like having to add resolved files to the index.
Imagine you know nothing about version control. Words like "unified diff" ring no bell. You've never seen conflict markers. You've never applied a patch or produced one.
Agree.
> I’d place it into the look-it-up-if-needed category.
Disagree. Bisect is so useful in so many different scenarios that learning about it and the basics of how to use it is a great way to get people into git. Obviously not right at the beginning of their learning curve but as soon as the basics have been covered satisfactorily.
Knowing how to use git bisect is what elevates a programmer to the next level. Just understanding how it works gives you a new way to reason about bug finding and fixing (or feature development using old and new), and then actually using it can make you a bug fixing master.
This was not my impression when I first learned about it. I thought I'd be using it all the time.
Just understating how git bisect works is the real superpower. The tool is a nice add on, but often you're right, is easier to bisect by hand by going to a known working commit and then doing a smart bisect based on the code you think might be offending.
But at least knowing the concept of bisection is a huge game changer.
Really feels like a stretch to credit git, of all things, with that fundamental understanding. It's like saying you need to operate a nuclear power plant to understand the benefits of locking doors.