How to ignore a tracked file in git without deleting it?

My team uses sourcetree as our git client. There is a third-party plugin in our project. It needs several configuration files. These files cannot be generated automatically. They store account name, login tokens and some temporary options, which shouldn't be shared. But everyone still needs this file, otherwise it will report error. So now they always stay in our "uncommitted changes" section which is annoying.

I have 2 options:

  1. Remove these files from git repository. Add them into .gitignore. Ask all my team members to add these files back to their local project with their own settings.

  2. See if there are tricks like "ignoring a tracked file without deleting it".

(Basically I feel if option 2 was possible, git should have some logic like "If local doesn't have this file, use remote version. If local has this file, ignore". The logic feels bad, easy to generate bugs.)


Solution 1:

This is what you want to do:

  1. Add all the files, individually or in a folder, that you want to remove from the repo but keep locally to .gitignore.
  2. Execute git rm --cached put/here/your/file.ext for each file or git rm --cached folder/\* if they are in a folder. (It is /\* because you need to escape the *)
  3. Commit your changes.
  4. Push to remote.

After having done this, you will effectively "ignore tracked files without deleting them", removing them from the repo and keeping all of them untouched in your system. Then when your team pulls the changes, they will pull the .gitignore file and their individual configuration files will not be overwritten by the ones in the repo because you have ignored them and deleted them from it. Also, because now the new .gitignore is ignoring these files, everybody will have their own version of them not showing in the "uncommitted changes".

Solution 2:

There seems to be an easy solution found here. Adding the file / directory to .gitignore only is not enough, but git will allow you to manually "ignore" changes to a file / directory:

git update-index --assume-unchanged <file>

And if you want to start tracking changes again, you can undo the previous command using:

git update-index --no-assume-unchanged <file>

Background: I needed this to add a configuration file with user data to the repo. The user should pull the file and edit it for his/her system, but the file should subsequently be ignored by git and never commited.

Solution 3:

tl;dr

  • Technically your requirement is contradictory.

  • At a more philosophical level it (seems) to be a clash between open source and corporate philosophy.

  • Anyhow… I'll suggest some things that come to my mind

Technically

git either tracks or ignores a file.

  • Tracking is easi(est). Just do nothing…other than using git! And any file is tracked.
  • Ignoring is nearly as easy — just make sure it matches something in your gitignore file.
  • But you cant do both!!
  • Main caveat: Moving a file from tracked to ignored is somewhat non-trivial — simply adding the suitable pattern to gitignore wont cut it once tracked. The relevant

Best Practice

Dont start a git project without creating a proper

  • gitignore
    Also related
  • gitattributes

So the first (and somewhat unrealistic)

Suggestion 1

  • Start a new git project
  • Make proper gitignore and gitattribute files
  • Debug if necessary with git-check-ignore
  • Copy,add,commit your normal files
  • Copy, add, status the not-to-be-tracked files. Status should be clean

But as I said this seems to be not quite what you want because you do want some kind of shared but untracked files. So you need to

Untrack tracked files

  • Clean tip (simple but likely inadequate solution
  • filter branch
  • filter-branch
  • Better alternative to filter branch

You actually want a git

Post-Clone hook

This is attempted here

But is a bad idea as explained here

Which brings me to the

Philosophical difference

  • A corporate-enployer justifiably wants to control what/how its employee-programmers function. Which entails various kinds of machine control
  • A random open source software sitting on github that takes control of some other random person's machine is unethical and illegal.

Therefore if you were a big fortune-500 player the natural option would be to fork git itself and add a post-clone hook feature in your fork

A more reasonable and only slightly more inconvenient

Solution 2

  • Write your own post-clone but manually callable script
  • … which does the requirement of copy if absent leave alone if present
  • And add a (manual) step to your team: (1) clone (2) call script
  • And dont forget the gitignore!!

If this solution makes sense you may actually prefer

Solution 3

Invert the script-inside-git to git-inside-script

ie ask your team to only download/copy and run a script that

  • Runs git clone
  • Checks for these other files' existence/propriety
  • Creates/downloads them if necessary (maybe from a source independent of your main repo)

Solution 4:

  1. Remove these files from git repository. Add them into .gitignore. Ask all my team members to add these files back to their local project with their own settings.

If I'm reading your question correctly, and the files in question contain such things as authentication credentials and site- or developer-specific configuration settings, then this is the way to go.

  • If there is any chance that your git repo will ever be made accessible to outside or untrusted entities, then your authentication details should not be in it because they will be disclosed to anyone who clones the project. Even if the credentials have been removed at some future point, they'll still be available in the history.

  • Site-/developer-specific settings don't raise the security issues that authentication information does, but they will still cause issues if multiple sites or developers are involved because, even if you have a policy against committing/pushing changes to those files, it's just a matter of time before someone commits them and causes everyone else's settings to be changed (or spurious conflicts to be generated) the next time they pull. I have personal experience with this one, and it's a major, ongoing nuisance to deal with. In our case, some of the differences were development vs. production settings, as well as site-specific settings, and this caused repeated adverse effects for our production systems.

One hacky workaround which I've seen several projects use is to make a sanitized copy of foo.cfg named foo.cfg.default, track foo.cfg.default in git, gitignore foo.cfg, and rely on the user to copy foo.cfg.default to foo.cfg after cloning and customize it (adding authentication credentials, personalized settings, etc.). In your case, since the config files are for a third-party plugin, this could work, since they're probably pretty stable. It's less effective in scenarios where foo.cfg.default will be frequently changing, since it then falls on the user to notice any changes and manually merge them into the local foo.cfg.

Solution 5:

There is no easy solution to this. But you can try out the following:

A) Put foo.cfg in .gitignore and push. Ask everyone to keep a save copy of foo.cfg outside their local repository. Let them push and copy that deleted file foo.cfg back in place.

B) Rename foo.cfg to foo.default.cfg put foo.cfg in gitignore, push and ask every member in your team to pull, then localy renaming foo.default.cfg to foo.cfg. After that, you need to delete foo.default.cfg, push, and everyone has to pull again.

C) Put foo.cfg in .gitignore and push. Ask everyone to pull. Now for everyone the foo.cfg is deleted. They can restory it by git checkout HEAD^ foo.cfg. Now the file is still staged, so they need to call git reset HEAD. Now it works.