But it isn't complicated! When you use a decent UI tool. I know pretty much exactly how VSCode's UI behaves with Git, along with the Git History plugin. And now I have a perfectly usable workflow and never have to use the command line, and almost never have any merge conflicts.
Maybe this is common knowledge to all of you, but it seems to me a lot of people have Git headaches, so maybe they don't know this?
1. Pull latest from remote main branch (select the branch, hit the sync button; permissions structure prevents any accidental pushes)
2. Create new branch based on pulled branch. If I have stashed work, apply it now.
3. Do work
4. Use the + icon to stage individual changes and give them their own local commit
5. Push my local branch to remote (hit that sync button again)
6. In my remote repo UI push the button to create a Pull Request (I assume all shared repos have a PR button somewhere?)
7. Go back to doing local work, but don't commit yet, and continue "not committing" for now
8. After the PR has been merged into main, stash everything including untracked (pick it from the VSCode menu)
9. Go back to step 1, repeat
Steps 7 and 8 are how you avoid creating your own merge conflicts. If you keep committing while a PR is in flight, then later on Git will see your earlier changes to a file, and your later changes to the same file, and will see them as a conflict. So just do yourself a favor and never commit to a branch while anything in its history is part of an in-flight PR. Obviously you'll have to deal with merge conflicts with other people but at least you aren't creating your own headache.
Git History saves me when I goof up and commit locally when I shouldn't. I just pull up the history and click the soft reset button prior to my commit and presto, I'm back where I want to be (files uncommitted, back in pending changes list).
Maybe one day I'll learn the Git command line, but right now why bother?