Most answers here say that it can't be done, or use stashing. It can be done without stashing, but it's not easy and it's not something you want to incorporate in your daily routine, I think.
For this example, I started with a main branch and a foo branch.
o--o--o (main)
\
o (foo)
I want to commit a file to main while foo is checked out. The commands I write here are all done without checking out main.
git add examplefile
git write-tree
# this returns a hash: 2ceb75e10358ba27aaf2291e4e302d759fbedd55
git commit-tree 2ceb75e10358ba27aaf2291e4e302d759fbedd55 -p main -m "commit message"
# this makes a commit with commit the main branch points to as parent
# it too returns a hash: 56823299cdc8b6c1ab30095f6b2c2143f3bb2122
git branch -f main 56823299cdc8b6c1ab30095f6b2c2143f3bb2122
# this points the main branch to the new commit
So what did we do? Essentially, we did all the steps a normal add-commit routine does, with some tweaks.
First, we add a file to the staging area just as normal. Next, we run git write-tree. That writes the staging area to a tree and returns the hash of that tree. A commit is not much more than a pointer to a tree, a pointer to its parent(s) and a message.
Then, we actually make the commit by giving it the three things it needs: the tree, the parent (main) and the commit message. Note on my computer this command doesn't open an editor for the commit message, so I need to give it in the command line. Your experience may vary.
The situation is then as follows:
o (new commit)
/
o--o--o (main)
\
o (foo)
We made the new commit at the right spot. However, it's dangling, meaning there is no branch (or tag) pointing to it. We now have to point main to the new commit.
The last command does exactly that. It takes the hash of the newly created commit and points main towards it.
Done!
As I said at the start: this is not something you want to do often. The normal add-commit strategy is well thought out. This strategy might mess up something you're not aware of. It doesn't check for conflicts, it just overwrites files without mentioning it.
Finally, a one-liner to do everything in one fell swoop:
git branch -f main $(git commit-tree $(git write-tree) -p main -m "commit message")
The hash output from write-tree is used immediately as an input for commit-tree, and its output is used immediately in moving the branch.