Git - handling frozen content

Almost all the projects that I worked on have some kind of "frozen content" that should always appear during cloning, but rarely change (see example below). I tried different approaches using git, but they are all error prone: people often cheat random changes.

This is a delicate case: files / folders should be versions, but the vast majority of changes should not be pushed.

Having looked around, I have a couple of options:

  • git update-index --assume-unchanged <file> : Problem - this will be a local parameter , so this solves the problem only on this machine. New clones tend to forget and still make changes by accident.
  • git update-index --skip-worktree <file> : Problem . The same problem appears, since I do not think that changes in the index are always propagating.
  • git rm --cached <file> : Problem - this is actually not a solution, as all toasts are copied when pressed!
  • echo <file> >> .gitignore : The problem is not the solution, as it controls whether the object is added to the repo.
  • use the smudge / clean filter to exclude file changes from commits (see jthill answer ): The problem is complex, error prone: every developer still needs to be configured locally.

A valid answer to this question does not require special actions by each new developer .

Why? Because this is precisely the problem with the above solutions, which, in my experience, lead to situations where "someone else committed this file."

Searches easily raise many questions. We need a definitive answer!

Example:

Here I am dealing with an ATM. My project is a website that has wiki software built in (which I did not write). The wiki component needs a nontrivial folder structure that is used more as a database (probably should be one). He should find folders and files that already work there. After some time, these files become large - we do not want to track these changes! This folder structure also contains some configuration (I know). If I could include a bare instance in a repo and somehow (almost) never track its changes, that would be great.

+6
source share
3 answers

It is not clear what file types you are talking about.

In the case of configuration files, I always recommend the following approach:

  • Commit an example configuration file with normal defaults, for example. config.sample.ini .
  • Ignore the file without a sample, for example. config.ini .
  • As part of the β€œrun” procedure on new machines, the config.sample.ini file must be copied to config.ini and configured. Document this process in your README, or wiki, or anywhere.
  • Make sure your code is "not working properly" if there is no configuration file, for example. When starting the software, an error will immediately occur: "Could not find config.ini. Have you copied the sample file?"

This ensures that the sample file can be easily updated. This ensures that the configuration file is not executed. He quickly copes if he is mistaken. And it's relatively simple to implement.

The fastest way to get from a dedicated config.ini ignored config.ini and a committed config.sample.ini is likely to do something like

 git mv config.ini config.sample.ini echo config.ini >> .gitignore git commit -a -m "Replace config file with sample config file" 

Update:

Your wiki example is interesting.

You are right that a deep tree of .sample files would be difficult to manage, but you can get the same effect with a zip file or archive:

  • Create an archive that will be tied to a repository containing your basic wiki content, for example. wiki.zip .
  • Ignore the directory where the wiki will be extracted, for example. path/to/wiki-root .
  • Add "extract wiki with unzip -d path/to/wiki-root " to your documentation. This is now part of your installation / deployment procedure.

Now you can update the zip file as needed and commit these changes, ignoring the changes in the extracted files.

+3
source

AFAIK, the only way to enforce the "do not change this" policy without voluntary action in each repo clone is to install the server side hook for them. A pre-check hook can check incoming commits for changes to the frozen file and reject them (if the commit message does not match some magic pattern that forces it to pass).

Server-side interceptors only work when managing a central repo, i.e. it cannot be on GitHub or any such service.

+3
source

Add the following file <proj-root>/.git/hooks/pre-commit to the project

 #!/bin/sh numFilesToVerify=0 IFS=$'\n' for l in `git diff --name-only --cached`; do while read m; do [[ $l == $m ]] && verify="$verify"`echo " * $l"`$'\n' && ((numFilesToVerify++)) done < .gitverify done if [ $numFilesToVerify -gt 0 ]; then echo "\nYou're changing $numFilesToVerify frozen files:"; echo "$verify" read -p "Do you know what you're doing? (yes/no): " reply < /dev/tty if [ "$reply" != "yes" ]; then echo 'commit aborted.' exit 1; fi fi unset IFS 

Then specify the files or directories that you want to freeze in the <proj-root>/.gitverify . Use wildcard * if you want:

 testdir/test* 

Here's what happens if I try to commit changes to the tesdir/test and testdir/test2

 $ git commit -m 'test' You're changing 2 frozen files: * testdir/test * testdir/test2 Do you know what you're doing? (yes/no): no commit aborted. 

Benefits:

  • I can easily add / remove files from the block list
  • If you update the tar part (see Chris's answer), you can overwrite the part that is not intended to be modified. No pitches are needed here, and that tells you what a potentially dumb thing you are doing.
  • does not use server interceptors, so there is no problem with access or with multiple remotes.
+1
source

All Articles