So let's say your main development line is the "main" branch. You start working on "bugfix", so you branch-off from "main". You do this on November 1.
So you make commits: "Fix bug". Then "Remove debug code", then "Rename X to Y". Now it's 10 days later.
Say a coworker is doing some other work at the same time, and just merged this into "main". You want to make sure that after that, everything still works properly. Maybe somebody changed something that makes the code you wrote no longer work, because somebody happened to fix a typo in a function's name or something, and you wrote your code against the old name which just ceased to exist.
So you do "git rebase main". What you're telling Git is "take the commits I made during the last 10 days, and apply them on top of the current main". It's like if you created a new branch then just applied the commits one by one by hand.
You can do this as often as you want, so if you've got some experimental refactor that takes you a month you can keep on rebasing daily to make sure that if there's any conflicts you have to deal with, you deal with it a little at a time, instead of having to figure out how to square a month of your work with a month of the rest of the project's work once you're done.
With this once you merge this into master, you get a "fast-forward" merge, which looks as if you were working on top of master all along. Instead of a single merge commit you see all 10 commits you made for the branch.
You can also do an "interactive rebase", where instead of having the process automated you can make decisions about each commit individually. This allows you to rename, merge, or discard commits. Like you've got 10 embarrassing looking commits where you just poke stuff at random in hopes of that it'll finally work? You can make them disappear entirely, or merge them all into one commit.
Applying a commit "on another branch" isn't really well defined in my mind. In my understanding, a commit consists of one or more parent commits, and the complete state of a tree, including the entire contents of all the files in it.
Maybe there are other ways to be confused, but all of the uncertainty has been shoved into that simple phrase "apply a commit on another branch". What does that actually mean?
If you haven't used git cherry-pick, then it is basically a shortcut for `git show $REF | git apply -`, where the short cut is the simplest form of using git, you have a patch (via git show) and you want to apply it to your local checkout.
Calculate the difference between the commit and its parent, and repeat that change against another branch.
So, like git log of your work over 10 days, git show each commit individually, then apply each patch that generates against the latest code.
Everything is merge.
Rebase also can produce merge conflicts when doing the rebase. Sometimes that makes resolving them easier and sometimes harder.
My preferred default would be to only ever merge, with an explicit merge commit at all points. (i.e. Never rebase, never use a fast-forward merge.) The main branch is then a sequence of merge commits, visible with "git log --first-parent". This is the same cleaned-up history that rebase proponents espouse, but doesn't lie about the true history the way a rebase-by-default workflow does
Interestingly enough, trunk based development is what all the big teams have arrived at also. It’s the only thing that works.
If trunk based development doesn’t work for you, it’s because you’re missing feature flags or can’t use them for a specific project. And it always leads to pain.
I know a lot of people like git flow for its ability to create seperate envs that can be controlled and tested, however it always felt extremely unnecessary to me when building saas products. Changes should not be long lived in this space.
I can understand how git flow would be great when the product is an artifact like a docker image, binary, vm image etc... but for managed applications / saas stuff, it's not the best.
As an aside, I think git complexity can arise for two reasons. One is legitimate, if you have hundreds or thousands of devs committing to the same repo regularly you need to have some order to the chaos otherwise it just will grind to a halt.
The other is bullshit. Where some dev / management people believe that the git process needs to be complex for small teams due to the need to justify their place by "promoting safety". In small team environments, simple branching off of main and then committing prs directly to main is more than enough in my opinion.
But git gives you the tools to go as crazy as you want, so some people do.