We've got a situation where a file in our repo should be locked in place, unchangeable going forward.
I've added the file to .gitignore
but when I modify it locally git still tracks it-- my understanding now is that adding files/folders to .gitignore after they're already in the repo doesn't work and that one possibility is to use git rm --cached file
to untrack them.
If I do, will the file no longer be available in the repo for the next person who clones it? Is there a better way to freeze this file in the repo?
It's not too hard to configure your own repos so they will never commit a change to that path, other repos' owners will have to cooperate to the extent of executing some one-time config commands.
Here's what you do for your own repo:
set up a content filter that will not alter existing content either in the worktree or in the repository.
git config filter.pinned-content.clean 'git show HEAD:%f 2>&- || cat'
git config filter.pinned-content.smudge 'cat %f 2>&- || cat'
git will execute the clean
commands to generate the content to be put in the repo whenever you stage (git add
) such files. Here, the commands try to show what's already committed for the file, and if that doesn't work, if nothing has been committed for it, then they'll take what you're staging. Likewise, git executes the smudge
commands to generate the content that should be put in the worktree on checkout, here using whatever's already there as-is, otherwise taking the content from the repository as a default.
advertise that you want path/to/file treated this way
echo path/to/file filter=pinned-content >>.gitattributes
make the treatment apply to all future checkouts/adds in this repo, even of already-existing commits
mkdir -p .git/info
echo path/to/file filter=pinned-content >> .git/info/attributes
Here's one way to distribute the request and instructions for cooperation:
# commit the new .gitattributes and explain what you need by way of cooperation:
git add .gitattributes
git commit -F- -- .gitattributes <<EOD
How to set up to preserve existing file content
# set up a content filter that will not alter existing content
# either in the worktree or in the repository:
git config filter.pinned-content.clean 'git show HEAD:%f 2>&- || cat'
git config filter.pinned-content.smudge 'cat %f 2>&- || cat'
# make the treatment apply to all future checkouts/adds in this repo
mkdir -p .git/info
echo path/to/file filter=pinned-content >> .git/info/attributes
-------
Please do the above configuration to avoid mistakenly committing local changes
to files marked with the `pinned-content` filter. Currently path/to/file is
marked in the committed `.gitattributes` to be treated this way, you can locally
mark files to be treated this way for even preexisting commits by adding a
similar line to your repository's `.git/info/attributes` file.
EOD
The %f
capability was included in 1.7.4, so it's been four years, it seems reasonable to expect distros have that available.
You can get a very similar effect with git's sparse checkout, but that won't handle supplying default content and can't be enabled through .gitattributes
.
This has passed smoketests and several hours of banging around, it doesn't look much like my first attempt at it.
If you want to "freeze" the file (prevent further changes being tracked in Git), you can run git update-index --assume-unchanged somefile
.
From the docs:
When the "assume unchanged" bit is on, the user promises not to change the file and allows Git to assume that the working tree file matches what is recorded in the index.
Further reading: git-update-index
NOTE: This does NOT prevent other people from changing the file. Everyone who clones the repo will have to run this command as well if you wish for the file to truly never change in Git.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With