Just in case you didn't know, there is git add -p (or --patch) which does precisely what you want: It splits your changes into small parts ("hunks") and allows you to specify whether to stage every hunk. I don't know your exact workflow in Sourcetree, but most likely git add -p is the CLI equivalent of the Sourcetree interaction you describe.

Bonus commands: -p/--patch also works for git stash (allowing you to stash only certain changes) and for git checkout (allowing you to discard only certain changes). Since I'm an Old School Git user I actually don't really know the restore/switch commands, but apparently git restore supports -p/--patch as well.

Another neat git add flag is -u/--update: The manpage is a little confusing on this flag, but essentially it makes git add ignore untracked files (it will only stage files that are already part of the repository). If you're like me, you have tons of files laying around in the project folder (e.g. benchmark results or local test input files) that you don't want to commit and yet don't want to add to the .gitignore file (since the files are really just temporary files, other users have no use for the gitignore entries). By using git add -u, you prevent adding them by mistake in a command like git add src/ and realizing a few weeks later that you accidentally added 10 MB of cat pictures to a bugfix commit. If you can identify with this story then git add -u is made for you.

Another bonus fact: If the temporary testing files mentioned in the last paragraph ever reach the status of permanent testing files, and they're still only useful to you personally (so adding them to gitignore doesn't make sense), Git has a little-known feature: You can add local ignore patterns (same syntax as gitignore) to .git/info/exclude (go ahead and check, this file most likely already exists in your Git repository). These patterns are not be part of the repository itself (you don't commit them), rather they act as local configuration. The idea is that you put exclude patterns that are valid for every user of the project (e.g. target/ for a Rust project) in .gitignore, and local exclude patterns for your IDE/editor configuration (.vscode/, .idea/ and friends) and similar files in .git/info/exclude.

In conclusion, I only every run a) git add -u $file (when I want to add all changes made to an existing file), b) git add -p $file (when I want to add only certain changes made to an existing file), or c) git add $new_file (when I consciously want to add a previously untracked file).

These three commands are all you need if you're in the camp of Git users that at least try to make every commit a good package (single, reasonably-scoped and atomic change). If you're in the git commit -a/"squash all intermediate commits into one single monstrous commit" camp then.. have fun with your cat pictures, I guess.

I hope that was at least a little bit helpful to someone.

May I ask why you drop into VS Code for interactive rebasing? Is it about resolving the merge conflicts, or editing the rebase command list?
I'm just going to drop two more nice Git features here, but I'll stop myself now before I write too much: git commit --fixup= together with git rebase --autosquash, and git rerere (not a typo).