I wouldn't consider rebasing your own local commits on top of a more recent remote master to be messing with history in any meaningful way, and that's the most useful method of rebasing.
Assuming "H" is the hash of the current state of the repository content, consider this initial state of the repository (most recent first):
H(3) Implement feature B
H(2) Implement feature A
H(1) Initial commit
Now you implement "shiny feature", so your history in your branch looks like this:
H(5) Shiny feature, improvements.
H(4) Shiny feature, initial implementation.
H(3) Implement feature B
H(2) Implement feature A
H(1) Initial commit
You tested H(4) and H(5), and everything looks good.
Then you `git pull --rebase`, and your history looks like this:
H(10) Shiny feature, improvements.
H(9) Shiny feature, initial implementation.
H(8) Pulled commit C
H(7) Pulled commit B
H(6) Pulled commit A
H(3) Implement feature B
H(2) Implement feature A
H(1) Initial commit
You test H(10) because it's the current state of your repo, looks good, and merge (or create PR, whatever).
With the usual pull request flows, `H(9)` (i.e. anything between your new "base" and your most recent commit) usually stays untested, entirely ignored by the developers, and you would only ever find out if you ever need to bisect.
Not usually a problem, unless you have a rule of "every commit should be verified/tested" and the untested commits have a change that doesn't prevent a build but still causes issues (e.g. something that's only visual, or a new config file was added to a "conf.d" directory and its presence changed some behavior, stuff like that).
To avoid this you can squash H(9) and H(10) before pushing to a shared branch, this way only one tested commit will be added on top of existing commits.
One of the great advantages of git is being able to pull from other people's feature branches, not just master. So protecting just master isn't good enough.
Isn't "protect your main branch" still the answer to this?
Your two feature branches would be unprotected so you can merge away if you like. When one of you wants to commit something to master, that's when you'd check for dodgy merges.
Also, "git cherry-pick" is a good alternative to merging for this use case.
Not good enough, that can mean you rebase changes that someone else has based further work on (but hasn't pushed it yet, or has pushed it to a different branch).
> Why are you having people base their work off your in progress work?
To collaborate more closely and reduce (or get ahead of) conflicts. The whole point of using git at all is to be able to base your work off other people's in-progress work; if you're not interested in doing that then Subversion works better.
Assuming "H" is the hash of the current state of the repository content, consider this initial state of the repository (most recent first):
Now you implement "shiny feature", so your history in your branch looks like this: You tested H(4) and H(5), and everything looks good.Then you `git pull --rebase`, and your history looks like this:
You test H(10) because it's the current state of your repo, looks good, and merge (or create PR, whatever).With the usual pull request flows, `H(9)` (i.e. anything between your new "base" and your most recent commit) usually stays untested, entirely ignored by the developers, and you would only ever find out if you ever need to bisect.
Not usually a problem, unless you have a rule of "every commit should be verified/tested" and the untested commits have a change that doesn't prevent a build but still causes issues (e.g. something that's only visual, or a new config file was added to a "conf.d" directory and its presence changed some behavior, stuff like that).