428

Every developer on my team has their own local configuration. That configuration information is stored in a file called devtargets.rb which is used in our rake build tasks. I don't want developers to clobber each other's devtargets file, though.

My first thought was to put that file in the .gitignore list so that it is not committed to git.

Then I started wondering: is it possible to commit the file, but ignore changes to the file? So, I would commit a default version of the file and then when a developer changes it on their local machine, git would ignore the changes and it wouldn't show up in the list of changed files when you do a git status or git commit.

Is that possible? It would certainly be a nice feature...

alex
  • 6,818
  • 9
  • 52
  • 103
Derick Bailey
  • 72,004
  • 22
  • 206
  • 219
  • 1
    See also http://stackoverflow.com/questions/3318043/mark-a-file-in-the-git-repo-as-temporarily-ignored on a similar topic. – VonC Jul 23 '10 at 16:57
  • possible duplicate of [Committing Machine Specific Configuration Files](http://stackoverflow.com/questions/1396617/committing-machine-specific-configuration-files) – Senseful Sep 03 '14 at 19:35
  • [git ignore files only locally](http://stackoverflow.com/q/1753070/995714) – phuclv Mar 20 '17 at 04:29

5 Answers5

528

Sure, I do exactly this from time to time using

git update-index --assume-unchanged [<file> ...]

To undo and start tracking again (if you forgot what files were untracked, see this question):

git update-index --no-assume-unchanged [<file> ...]

Relevant documentation:

--[no-]assume-unchanged
When this flag is specified, the object names recorded for the paths are not updated. Instead, this option sets/unsets the "assume unchanged" bit for the paths. 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. If you want to change the working tree file, you need to unset the bit to tell Git. This is sometimes helpful when working with a big project on a filesystem that has very slow lstat(2) system call (e.g. cifs).

Git will fail (gracefully) in case it needs to modify this file in the index e.g. when merging in a commit; thus, in case the assumed-untracked file is changed upstream, you will need to handle the situation manually.

Fail gracefully in this case means, if there are any changes upstream to that file (legitimate changes, etc.) when you do a pull, it will say:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext
 

and will refuse to merge.

At that point, you can overcome this by either reverting your local changes, here’s one way:

 $ git checkout filename.ext

then pull again and re-modify your local file, or could set –no-assume-unchanged and you can do normal stash and merge, etc. at that point.

Community
  • 1
  • 1
Rob Wilkerson
  • 40,476
  • 42
  • 137
  • 192
  • hmmmm that could be exactly what i'm looking for! thanks rob! i'll try it out and back to ya. :) – Derick Bailey Jul 23 '10 at 17:40
  • 1
    if you want to **start tracking changes again** run the following command: `git update-index --no-assume-unchanged ` – agustibr Nov 24 '14 at 14:42
  • 18
    does this command do its thing locally of in the .git folder? I mean, if I run this command for a config.php file, will this propagate to other users that are using the repo? – Magus Feb 10 '15 at 00:01
  • 22
    @Magus: No. This will only operate for you. – Rob Wilkerson Feb 10 '15 at 12:18
  • 4
    And soon later you are going to want to know how to determine is a file is assumed unchanged: http://stackoverflow.com/questions/2363197/can-i-get-a-list-of-files-marked-assume-unchanged – Ciro Santilli OurBigBook.com Feb 20 '15 at 15:52
  • 1
    @RobWilkerson: anyway to make git create the file upon `clone`, but ignore subsequent changes in diffs and `commit -a`? – Gauthier Apr 24 '15 at 08:36
  • Assuming that what you're basically asking is whether git can create a brand new file during the clone process, then no. Not to the best of my knowledge. The cloning process only clones what in the repo as far as I've ever known, but I guess I've never had a reason to need/expect anything else. – Rob Wilkerson Apr 24 '15 at 12:11
  • If I use this command, will I still see changes to the file on origin and pull those in? (I have a slightly different use case from the original question) – nhgrif Mar 07 '16 at 20:58
  • 10
    Changes to files ignored in this way are lost when "git stash" is used . Is there a way around that? – Alexis Oct 04 '16 at 10:41
  • 6
    This is not what `git update-index --assume-unchanged` is for. https://public-inbox.org/git/xmqqy4z5go1y.fsf@gitster.dls.corp.google.com/ – jsageryd Aug 02 '18 at 15:30
  • This doesn't seem to be working for other users since running the command will not require any commits to the repository. I am guessing this has to be done locally per user cheking out the project. – mjs Feb 04 '19 at 12:48
  • Nowadays, the porcelain has an equivalent: `git add --intent-to-add`. [See here](https://git-scm.com/docs/git-add#git-add--N) – jpaugh Feb 12 '19 at 18:55
  • The [Git documentation](https://git-scm.com/docs/git-update-index#_notes) specifically says not to do this. – bk2204 Apr 28 '20 at 22:57
  • Didn't ignore the modifications I wanted to stay local. As other posters have mentioned, git does not include any (reliable) mechanism to ignore changes to tracked files, so you must provide your own alternatives. – Suncat2000 Jul 07 '20 at 14:43
118

The preferred way to do this is to use git update-index --skip-worktree <file>, as explained in this answer:

assume-unchanged is designed for cases where it is expensive to check whether a group of files have been modified; when you set the bit, git (of course) assumes the files corresponding to that portion of the index have not been modified in the working copy. So it avoids a mess of stat calls. This bit is lost whenever the file's entry in the index changes (so, when the file is changed upstream).

skip-worktree is more than that: even where git knows that the file has been modified (or needs to be modified by a reset --hard or the like), it will pretend it has not been, using the version from the index instead. This persists until the index is discarded.

To undo this, use git update-index --no-skip-worktree <file>

Since git version 2.25.1, this is no longer the recommended way either, quoting:

Users often try to use the assume-unchanged and skip-worktree bits to tell Git to ignore changes to files that are tracked. This does not work as expected, since Git may still check working tree files against the index when performing certain operations. In general, Git does not provide a way to ignore changes to tracked files, so alternate solutions are recommended.

For example, if the file you want to change is some sort of config file, the repository can include a sample config file that can then be copied into the ignored name and modified. The repository can even include a script to treat the sample file as a template, modifying and copying it automatically.

1615903
  • 32,635
  • 12
  • 70
  • 99
  • 1
    Does this work across all users that checkout the repository? Will they get certain files but no longer be able to add changes, by mistake, unless explicitly saying so? – mjs Feb 04 '19 at 12:48
  • 3
    @momomo the flag is stored in the index so no, it is only for a single user. See [erjiang's answer](https://stackoverflow.com/a/3319626/1615903) for something that works across all users. – 1615903 Feb 05 '19 at 05:04
  • I am trying to figure out what the contents of the file should be. I commented on the answer you referred to, but got no answer. Where is it supposed to be located and what is it's contents? Do you know? – mjs Feb 11 '19 at 10:15
  • I'm not following. The command is used to ignore one specific file that you specify in the command. Contents of that file is not relevant. – 1615903 Feb 11 '19 at 10:18
  • 2
    The [Git documentation](https://git-scm.com/docs/git-update-index#_notes) specifically says not use `git update-index --skip-worktree` for this purpose. – bk2204 Apr 28 '20 at 22:57
  • >For example, if the file you want to change is some sort of config file, the repository can include a sample config file that can then be copied into the ignored name and modified. The repository can even include a script to treat the sample file as a template, modifying and copying it automatically. This answer should be updated to show HOW to do this. In fact, the history of it isn't as interesting as the current recommended working solution. – Emir Feb 17 '22 at 15:58
  • 1
    @Emir this method works just as good as it always has, git has just updated the documentation to note that they do not recommend it. Other answers cover other options - this is mainly for cases where you are not in control of the remote and need some sort of workaround. – 1615903 Feb 18 '22 at 07:23
  • 1
    Thanks, good to know. I think it's my mistake. I misunderstood not recommended as not working correctly. I appreciate your follow-up. In fact, this answer solved my problem. – Emir Feb 18 '22 at 09:15
51

Common practice seems to be to create a devtargets.default.rb and commit it, and then instruct each user to copy that file to devtargets.rb (which is on the .gitignore list). For example, CakePHP does the same for its database configuration file which naturally changes from machine to machine.

erjiang
  • 44,417
  • 10
  • 64
  • 100
  • 6
    You can't .gitignore a file that is being tracked. .gitignore only has an effect for files that aren't in the index. – CB Bailey Jul 23 '10 at 16:30
  • 1
    i was trying to avoid doing this, though i really don't have a good reason. we're doing it now and i think it's a pain to remember that i need to create my own version without ".default" in the name. – Derick Bailey Jul 23 '10 at 17:39
  • 12
    @DerickBailey But to be fair, it's easier to remember to copy the file than to remember using the `--assume-unchanged` option for everyone who clones the repository. – Dan Jan 15 '16 at 13:15
  • 1
    @DerickBailey you could also set up your rake build to default to `devtargets.default.rb` if `devtargets.rb` doesn't exist. – Luke Willis Sep 30 '16 at 20:07
  • @erjang what is in that devtargets.default.rb file ? An example? – mjs Feb 05 '19 at 09:50
  • @momomo yeah, from the question originally – rogerdpack Jan 16 '20 at 16:22
  • Only practice I found satisfactory (simple, doesn't require a bunch of people to execute a bunch of git-commands in sync...). I still don't know why git wouldn't have this feature, it's clearly desired by many. – Nathan Chappell Jan 27 '23 at 14:42
6

It is not possible to ignore changes to a tracked file with Git. The Git FAQ explains this:

Git doesn’t provide a way to do this. The reason is that if Git needs to overwrite this file, such as during a checkout, it doesn’t know whether the changes to the file are precious and should be kept, or whether they are irrelevant and can safely be destroyed. Therefore, it has to take the safe route and always preserve them.

It’s tempting to try to use certain features of git update-index, namely the assume-unchanged and skip-worktree bits, but these don’t work properly for this purpose and shouldn’t be used this way.

If your goal is to work with a configuration file, then the best thing to do is add an example or template file and then either have the user copy it into place or have a script create the appropriate file. You should then ignore the location of the actual configuration file and only check in the example or the template.

bk2204
  • 64,793
  • 6
  • 84
  • 100
2

For IntelliJ IDEA users: If you want to ignore changes for a file (or files) you can move it to different Change Set.

  • Head over to Local Changes (Cmd + 9)
  • Select file(s) you want to ignore
  • F6 to move them to another Change Set
Eugene
  • 59,186
  • 91
  • 226
  • 333