Annoying executable reporting on NTFS drives in Linux
I have a shared NTFS drive between Linux and Windows. In Linux I mount the NTFS drive with the 'exec' option (as default) so I can compile and run binaries. However 'exec' makes all files within the drive executable.
When I try to colocate a git repo on this drive, jj reports every file as being modified to be executable. While they all are executable, I don't want this represented as a change in the repo. Running jj chmod normal <some_file> does nothing because the drive is mounted with all files executable, and jj continues to report everything as modified to be executable.
Git has an option for this as core.fileMode.
Here is git's documentation: https://git-scm.com/docs/git-config#Documentation/git-config.txt-corefileMode
core.fileMode
Tells Git if the executable bit of files in the working tree is to be honored.
Some filesystems lose the executable bit when a file that is marked as executable is checked out, or checks out a non-executable file with executable bit on. git-clone[1] or git-init[1] probe the filesystem to see if it handles the executable bit correctly and this variable is automatically set as necessary.
A repository, however, may be on a filesystem that handles the filemode correctly, and this variable is set to
truewhen created, but later may be made accessible from another environment that loses the filemode (e.g. exporting ext4 via CIFS mount, visiting a Cygwin created repository with Git for Windows or Eclipse). In such a case it may be necessary to set this variable tofalse. See git-update-index[1].The default is true (when core.filemode is not specified in the config file).
I'm not sure how an option like this might integrate with JJ's use of executable bits in windows, but it would be nice to add some solution for filesystems on Linux that can't easily control the executable bit.
I think it's probably feasible to have a mode where jj ignores the executable bit of files in the worktree and jj chmod (newly renamed to jj file chmod) is the only way to set/remove the executable bit. It could be specified with jj config set --repo.
I'm surprised this is not more of a problem, actually. I'm guessing this might show up when using WSL as well. I can't decide whether this deserves a Windows tag, but I guess it ultimately does since it's Windows filesystems that don't have an executable bit.
Sounds like we should replace the current compile-time switches between Windows and Unix by a runtime switch, which would then always be false on Windows and read from config on Unix.
@wrzian, if you're interested in implementing it, see how it's currently done in https://github.com/martinvonz/jj/blob/main/lib/src/local_working_copy.rs. Just search for "executable" there. We would probably want to pass the config into LocalWorkingCopyFactory.
We would probably want to pass the config into
LocalWorkingCopyFactory.
Actually, that will make it harder to initialize it because we typically don't have the settings available when we want to initialize the LocalWorkingCopyFactory. So maybe we'll need to pass &UserSettings to init_working_copy() and load_working_copy() instead.
FYI @ilyagr you're right, it is a big problem in WSL because the canonical way to access Windows OS files from WSL is via /mnt/, which is all executable by default, so this is super annoying when the repo lives in Windows but you open it in WSL.
My guess is that most users don't mix WSL and Windows on a single repo. I certainly don't.
Until the config becomes available, is there a short term solution to this - how do I avoid committing this as a "change" to the repo? Is the solution currently just "don't mix WSL and Windows", so the repo needs to be moved to be not on the Windows filesystem?
I've accidentally left the PR alone for a while since I've been focusing on other things, but you should be able to download and compile my branch from #4478 and use that binary until this gets merged (one of the reasons I haven't brought it to completion is that it's been working fine for me like that 😅).
As a partial fix I added the following to my zsh config:
function isWinDir {
case $PWD/ in
/mnt/*) return $(true);;
*) return $(false);;
esac
}
function git {
if isWinDir;
then
git.exe "$@"
else
command git "$@"
fi
}
function jj {
if isWinDir;
then
jj.exe "$@"
else
command jj "$@"
fi
}
This makes sure the windows version of jj is run when in the windows directory, thus bypassing the issues in this ticket. It does require one to have both a windows and WSL jj installation with separate config files, but it is a small issue.
Edit: If you need to run the function above in not logged in shells, such as running a watch in a zellij pane for jj diff or jj log, then you can run the following:
watch 'zsh -c "source ~/.zsh/.wsl; jj diff"'
Make sure and change the sourced file to the location of your own function above. This will allow you to run the windows version of jj in a non-logged in shell. One could add --ignore-working-copy to the diff to get around this issue of file executability being updated. But in this case I wanted the watch to update the files, so I did not have to manually run jj st or the like on every change.