#StackBounty: #linux #permissions #users #sshfs git over sshfs (with idmap): unable to append to '.git/logs/HEAD': Permission d…

Bounty: 100

Problem:

I have a git repository mounted via sshfs and cannot commit changes with the following error message:

fatal: cannot update the ref 'HEAD': unable to append to '.git/logs/HEAD': Permission denied

Note that I can

cp -a .git/logs/HEAD .git/logs/HEAD.bu
printf foo > .git/logs/HEAD
mv .git/logs/HEAD.bu .git/logs/HEAD

without a problem, but

printf foo >> .git/logs/HEAD

gives me the ‘Permission denied’ as well.

Question:

What do I need to change about my configuration to be able to commit from my local machine to the remote repository?

What I tried:

I given the above symptoms I assume the issue lies with appending to a file.
I found Git repository on SSHFS: unable to append to '.git/logs/HEAD': Invalid argument which refers to https://github.com/libfuse/sshfs/issues/82 suggesting the issue (note the slighty differerent error message) could be solved by mounting the remote file system with writeback_cache=no. The latter source quotes the man page referencing the following caveat/workaround:

CAVEATS / WORKAROUNDS
[...]
   O_APPEND
       When  writeback  caching is enabled, SSHFS cannot reliably support the O_APPEND open
       flag and thus signals an error on open.  To enable support for  unreliable  O_APPEND
       (which  may  overwrite  data if the file changes on the server at a bad time), mount
       the file system with -o unreliable_append.

However, this section is not in my man page:

sshfs -V
SSHFS version 3.7.0
FUSE library version 3.9.1
using FUSE kernel interface version 7.31
fusermount3 version: 3.9.1

I found that the writeback-cache feature that I tried to disable, was actually removed (after being disabled and re-enabled more than once before).
So I guess I should be good but clearly there (still) is a problem.

A further complication that I should probably mention, is that my user name and ID on the remote system do not match the local one, so I need to used the idmap feature.

Here is the corresponding fstab entry:

<remote-user>@<remote-machine>: /mnt/ssh/<remote-machine>  sshfs  _netdev,user,idmap=user,allow_other  0 0

Also, my /etc/fuse.conf contains

user_allow_other

Background:

To avoid answer just telling me not to do this:

  • I know how git works.
  • I know I can clone the repository locally, commit there, and push to the remote one over ssh.

Why I don’t do it? – Because I track code that can only be tested on the remote machine and I do want to test it before committing.
So to some extent this is ‘just’ a convenience issue to avoid having to:

  1. Edit code on the local copy.
  2. Commit the changes to the local copy.
  3. Push to the remote copy.
  4. SSH to the remote machine (or switch terminals).
  5. Test the code on the remote machine.
  6. Checkout another branch (to allow force-pushing).
  7. End the SSH sessions (or switch [back] terminals).
  8. Edit the code.
  9. Amend the previous commit on the local copy.
  10. Force-push to the remote copy.
  11. SSH to the remote machine (or switch terminals).
  12. Checkout the force-pushed branch.
  13. Repeat steps 5 – 11 (seven steps!) until I’m happy.

Instead, I want to:

  1. SSH to the remote machine (or switch terminals).
  2. Edit code on the remote copy from the remote machine.
  3. Test the code on the remote machine.
  4. Edit code on the remote copy from the remote machine.
  5. Repeat steps 3 – 4 (two steps!) until I’m happy.
  6. End the SSH sessions (or switch [back] terminals).
  7. Commit the changes to the remote copy from the local machine.

Why don’t I simply commit from the remote machine? – Because I want to sign my commits but can’t entrust the remote machine with the private key.
So the best alternative I could come up with is:

  1. SSH to the remote machine (or switch terminals).
  2. Edit code on the remote copy from the remote machine.
  3. Test the code on the remote machine.
  4. Edit code on the remote copy from the remote machine.
  5. Repeat steps 3 – 4 (two steps!) until I’m happy.
  6. Commit the changes to the remote copy from the remote machine.
  7. Checkout another branch (to allow force-pushing).
  8. End the SSH sessions (or switch [back] terminals).
  9. Pull from the remote copy.
  10. Amend (sign) the previous commit on the local copy.
  11. Force-push to the remote copy.
  12. SSH to the remote machine (or switch terminals).
  13. Checkout the force-pushed branch.

So on the one hand, I’d like to get rid of these extra steps (things get more complicated when adding feature branches as those need to be properly checked out on both copies and configured for proper tracking), on the other I want to understand why it doesn’t ‘just work'(tm).


Get this bounty!!!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.