78

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.)

6 Answers 6

66

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".

[EDIT]:

IMPORTANT NOTE!

As @ardila mentions, please note that executing this procedure will cause the deletion of the files for all those who pull these changes. To avoid this issue just make a backup of all those files you want to keep first, then perform the pull which will delete the files, and finally just restore the backed up files. Now from this point onward these files will not be erased or updated with the upstream changes on every pull (since they have been ignored already)

4
  • 16
    While it is true that this will work for develops who already have the file locally, you have indeed deleted it from git and anyone checking out the repo anew after you commit the git rm changes will not have the file in their working copy.
    – ardila
    Apr 17, 2020 at 19:58
  • 3
    @ardila This is true. A simple remedy is to create a script whether npm or powershel or anything else, that can be run once for new users of the repo and generate the gitignored file. Or, just tell them how to manually setup that gitignored file if it cannot be generated.
    – TetraDev
    Aug 26, 2020 at 17:21
  • One could just keep a tagged commit with all the files needed and have a git hook run git clone <repo_url> --branch <tag_name> --single-branch whenever those files are not present...
    – Beto Frega
    Dec 4, 2020 at 16:55
  • 3
    @ardila 's comment needs to be emphasized. This will remove the files on others filesystems once they checkout a branch that contains this change. It's exactly what the OP was trying to avoid.
    – James
    Aug 27, 2021 at 15:02
33

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>

To view files for which change tracking is disabled, you can use (linux/unix):

git ls-files -v | grep ^[h]

or (windows):

git ls-files -v | find "h "

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.

5
  • 2
    Notice, ALL git users that want to modify the file, should run the command above.
    – itsho
    Oct 11, 2021 at 12:52
  • To view files with change tracking disabled in linux/unix I've found that git ls-files -v | grep "^h" works nicely.
    – Mogsdad
    Oct 31, 2022 at 17:34
  • @Bim Will this allow the file to be pulled from the remote if changes to the file were pushed to the remote? (It would require the user to redo their local changes, but at least, ignoring the local changes, the file will always be up to date with respect to the remote. That's useful for config files, where the user needs to make local changes that shouldn't be committed/pushed but are sometimes changed on the remote.)
    – RobH
    Apr 12, 2023 at 16:39
  • It should work (tm), but this is so long ago, I have no idea. You could try it and comment. I will update the answer.
    – Bim
    Apr 12, 2023 at 21:40
  • More info on the update-index --assume-unchanged approach and why maybe you might want update-index --skip-worktree instead, can be found here: stackoverflow.com/a/20241145/619961.
    – ikaerom
    Mar 14 at 13:51
2
  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.

2

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.

1
  • Making an external backup is not necessary because they can checkout the old file from an old commit.
    – lucidbrot
    Jul 17, 2020 at 11:15
1

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

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)
0

What you could do is to stash the files whose modification you don't want to track :

git stash push <path/to/file> <path/to/other/file>

They won't be added if you use git add . or git add -a as long as they are not modified. If the modification are frequent, you can create an alias to this command.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .