Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
998 views
in Technique[技术] by (71.8m points)

git - How to freeze a file in a repository

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...