I'm trying to understand the workflow when using feature branches in Git.
Is the final step in integrating any change from a feature branch always ultimately a merge
(the exception being if I want to maintain my own separate branch of a project)?
And is rebase
an alternative to merge
in the steps prior to the final integration which mainly affects the way the history is preserved?
When you use feature branches for your development work, yes, you always need to use a merge to bring your work into your main branch, once it's ready.
Rebases can be useful to clean up your feature branches before merging them in.
In my workflow, I almost always work on a branch when I'm implementing some feature or fixing some bug.
The history in the branch might be messy, and there might be changes to main that I need to incorporate.
To clean up my messy history, I typically use an interactive rebase.
To incorporate changes made by others in main, sometimes I rebase my branch onto main, but sometimes I merge main into my branch. Both options works fine, it just depends on what I think is most suitable each time (I don't have hard rules here, though, it's more of a feel).
Then, when my feature or bug fix is ready to incorporate into main, I merge it into main. That takes my branch's history and incorporates it in main's history.
Now, here, there might be two kinds of merge I'll use: if the branch was only one commit, I'll probably fast-forward merge it into main, making sure the commit log gave all the details I wanted the main history to have about the feature.
If the branch had a lot of commits, I'll use a non-fast-forward merge (i.e., a merge that creates an actual merge commit) so that I can summarize in the merge commit log what the feature is, at a high level. With two or three commits, I might go either way.
Finally, there is a third kind of merge that GitHub proposes for PRs: a "rebase merge". But that's not really a new kind, it's just that GitHub will do the rebase onto main for me and then do a fast-forward merge. I typically use this only for PRs that have just one or two commits, again, when I don't feel the need to document in the merge commit what the branch contributes.