Why is git creating read-only (444) files?
Those files are part of the object database, which really is read-only. No matter what you do with Git, you can't change the contents of a specific object once it has been created.
Note that if you back out a commit and create a new one in its place, you'll be creating a new object with a new identifier and new contents. Git will eventually perform its garbage collection to remove the old, unreferenced object(s).
`.git/objects/` directory contents: make git set the write permission instead of 'read-only'
My answer below isn't so much a solution for your problem, just more explicit information about why and where the git maintainers made this choice.
See: Why is git creating read-only (444) files? That stack overflow question references the relevant source code and documentation.
I couldn't find any relevant setting(s).
This git behavior causes an issue for me with a personal, local, offline, bare git repo. I need everything in the .git dir to be user-writable because I use a custom bitrot detector, and that bitrot detector works by writing a checksum to extended file attributes for later verification. Sure would be nice if there were a git configuration option around this, but I'm guessing writable index files is an edge case and the git maintainers might not even accept a patch to add one. Or they might.
I'm sure you're past all the rest below, but I'll include it for completeness and for anyone else who wants these git internal files to have more open permissions.
I imagine the git maintainers use 0444 perms for these files and I basically agree with their decision, so I use a fairly brute-force workaround. Before I run my bitrot detector, I give myself write permission:
find .git/objects/ -perm /u+w | xargs -r chmod u+w
and I remove it afterwards with:
find .git/objects/ -perm /u+w | xargs -r chmod u-w
Since git is "special" with its read-only files, maybe alias gitnuke
(or make it a function) to rm -rf
or do a find
workaround like I did above. Side note: I usually use rm -rf
to recursively delete any directory tree anyway, so I've never run into the problem you face.
Git: Track permission change 777 to 444
You could remove the file from your repository and replace it with the file that you changed.
What file permissions should the contents of $GIT_DIR have?
Directories should have 755 permission; files should have 644 permission.
That's a pretty good rule of thumb unless you expect members of your group to make changes to your repository.
Having said that, in one of my repositories, the files under .git/objects/*
have 444 (readonly) permission for everyone. Other files are 644 as suggested.
This script, run in the top-level directory just above the .git
repository would fix the permissions:
find .git -type d | xargs chmod 755
find .git/objects -type f | xargs chmod 444
find .git -type f | grep -v /objects/ | xargs chmod 644
I started with -print0
for the first two find
commands and xargs -0
to allow for the remote possibility of spaces in file names. But the grep -v
in the third command would be difficult to manage with the -print0
format - so I omitted the space-safe notation from all the commands, knowing that git
does not create files with spacing in names under the .git
directory.
How to restore the permissions of files and directories within git if they have been modified?
Git keeps track of filepermission and exposes permission changes when creating patches using git diff -p
. So all we need is:
- create a reverse patch
- include only the permission changes
- apply the patch to our working copy
As a one-liner:
git diff -p -R --no-ext-diff --no-color \
| grep -E "^(diff|(old|new) mode)" --color=never \
| git apply
you can also add it as an alias to your git config...
git config --global --add alias.permission-reset '!git diff -p -R --no-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply'
...and you can invoke it via:
git permission-reset
Note, if you shell is bash
, make sure to use '
instead of "
quotes around the !git
, otherwise it gets substituted with the last git
command you ran.
Thx to @Mixologic for pointing out that by simply using -R
on git diff
, the cumbersome sed
command is no longer required.
Git: Track permission change 777 to 444
You could remove the file from your repository and replace it with the file that you changed.
Diagnosing a git error -- fatal: adding files failed
The error message:
error: insufficient permission for adding an object
to repository database .git/objects
is close, but is potentially missing a few extra details. Git's object store (a simple key-value database) is currently implemented as a directory (or folder, if you prefer that term) named .git/objects
that contains numerous subdirectories (subfolders). Each directory must allow writes by the current user and/or group, with permissions being determined and managed by the operating system (not by Git itself, except as described below).
On a Unix or Linux like system (as you appear to be), permissions to read and write individual files are controlled by the file's permissions, while permissions to create new files or delete existing files (or create and/or delete subdirectories) are controlled by both the execute and write permissions bits of the various directories.1
Git will try to create new directories named .git/objects/xx
where the xx
represents any two hexadecimal digits if and when Git needs to add an object whose hash ID begins with those two digits. It will then try to create a new file in that directory where the file's name is the remainder of the hash ID (i.e., after stripping off the first two hexadecimal digits).
Besides the xx
directories, there's a directory named pack
that will be created as soon as there are any pack files (these contain packed objects, while the two-hex-digit directories contain loose objects; the difference is that the packed objects are more-compressed, and also try to work around bad performance of file systems with many loose objects). The pack
directory and files within it behave the same way as the loose object directories.
When creating a new directory, Git calls the OS's mkdir
with permissions 0777
. Your umask, which will generally be either 002 or 022, will clear the write permission for others (result 0775) or group-and-others (result 0755) respectively. Git uses the core.sharedDirectory
setting, if it exists, to set its umask relatively early on, in case you need these to be group-writable: this is normally only the case for a shared repository. Setting core.sharedRepository
to true
or group
causes all of these to be group-writable.
Because you appear to be using Docker (modified: .devcontainer/Dockerfile
) and Docker can result in UID and/or GID mapping, you might need shared-repository mode, even if you're working alone, and even that might not suffice. See appropriate Docker documentation to find out whether you're doing ID mapping and if so what you might need to do about that.
Otherwise—if you're not trying to share the .git
repository across a docker mount or if you're doing this in such a way that ID mapping is irrelevant—just make sure you have not incorrectly set up the existing directories within .git/objects
. In general, they should be:
- files: mode 0444; Git writes such files once, and then does not change them, so they're deliberately read-only
- directories: mode 0755 or mode 0775 depending on
core.sharedRepository
You can set them to mode 0777
, and set core.sharedRepository
to world
or all
or everybody
, if you have both UID and GID mapping going on in such a way that this is necessary.
Use chown
and/or chmod
recursively as shown in Yigit Yasar's answer but with the correct options to adjust the ownership and/or permissions of files. Note that you want:
chown -R user:group
(not group:user
) if you need to change these, and:
chmod -R g=u
(or chmod -R go-u
) to add group (or group and other) write and/or execute permissions to match the user permissions if you need group and/or world writable settings. In general, don't make the permissions any looser than necessary—this isn't because Git will break, but just a matter of general "permissions hygiene" where we don't want our systems to be too easy to attack.
1Specifically, write permission on a directory implies that you can create or delete a name within that directory. Execute permssion on a directory implies that you can use that directory to look up files. Read permission just means you can see what files are in it—you can still use the files if you know their names, even if you can't read it, as long as you can "execute" the directory. (However, some network file systems require both read and execute permissions.)
How to make sure others people cannot edit my git notes?
I don't think you really can protect published git notes.
What you can do is put them in an explicit namespace, as mentioned in here:
I think for "typical usage" one stores others' notes in a different place anyways, e.g. I store Thomas' list-notes in refs/remotes/trast/notes/ so that they don't interfer with my own notes.
If in the same namespace, then they can be merged:
git checkout refs/notes/commits
git fetch origin refs/notes/commits
git merge FETCH_HEAD
git update-ref refs/notes/commits HEAD
git checkout master
But that would change their content.
Related Topics
How to Get Exit Code of Remote Command Through Ssh
Setting Up Sonarqube on Aws Using Ec2
How to Use Performance Counters Inside of The Kernel
Undefined Reference to Symbol 'Timer_Settime@@Glibc_2.3.3
How to Get Use Count from Linux Kernel Module
Window Placement: Winsplit Revolution -Like Application for Linux (Kde)
How to Move Old File to Another Folder
Linux: Processes and Threads in a Multi-Core Cpu
How to Grep for Strings with Special Characters Like []
How to Set CPU Load on a Red Hat Linux Box
How to Create a Virtual Device in Linux
Unix Cut Except Last Two Tokens
/Usr/Bin/Env Questions Regarding Shebang Line Pecularities
Where Does Dmidecode Get The Smbios Table
Is Overwriting a Small File Atomic on Ext4