When you run git commit from a bash or other shell session, Git invokes your editor-of-choice.1,2 Git then waits for this editor to signal to Git that it is done, after which Git reads the file that the editor presumably updated by this point. But some editors immediately signal that they are done, and this is when the problem occurs.
If you are using such an editor, you have three choices:
Switch to a different editor that is not so badly behaved.
Find some way of running your favorite editor that tells it to behave better. Most of these editors have an option, usually spelled w or wait or --wait or -w or something like that, to make them behave well for Git.3 See, e.g., How to fix git commit with atom text editor.
Use git commit such that it always has a prepared commit message (git commit -m, git commit -F, and the like). This is probably the worst method, though.
For VSCode specifically, see How to use Visual Studio Code as default editor for git?, but note that VSCode is complicated and not all of the extensions for it play nice. That's probably why there are more than a dozen answers to this question.
1Run git var GIT_EDITOR to see what your choice is. Use any of core.editor as a git config setting, or $EDITOR or $VISUAL or $GIT_EDITOR as an environment variable, to change the setting. See the git var documentation for more about how Git picks which setting to use if you provide multiple settings.
2More precisely, git commit looks to see if it's been provided a "pre-cooked" commit message, and it can use that directly without having to invoke your editor-of-choice. But this problem only comes up when it's using your editor and waiting for it.
3Their behavior is actually fine for certain GUIs, and these editors were written with those GUIs in mind. It's just bad for Git.