git ignore vs. exclude vs. assume-unchanged
Asked Answered
S

4

99

I've read the docs on this several times over and I still don't completely get the differences between these different commands. Maybe it's just me, but the documentation could be more lucid:

http://git-scm.com/docs/gitignore

https://help.github.com/articles/ignoring-files

Moreover, a lot of the commentary on this subject seems to use the words "indexed", "committed", "tracked" somewhat loosely, which makes the differences between these three less clear.

My current (admittedly limited) understanding:

  • Files matched in .gitignore will not be tracked in the future. (Though they may have been tracked previously.) This means that they won't ever show up in a future git status list as changed. However, future changes will still be synced with remote repos. In other words, the files are still "indexed", but they are not "tracked". Because a .gitignore file is in the project directory, the file itself can be versioned.

  • Files matched in .git/info/exclude will also not be "tracked". In addition, these files will not ever be remotely synced, and thus will never be seen in any form by any other users. These files should be files that are specific to a single user's editor or workflow. Because it is in the .git directory, the exclude file can't itself be versioned.

  • Files that have had assume-unchanged run on them also don't show up in git status or git diff. This seems similar to exclude, in that these files are neither "indexed" nor "tracked". However, the last version of the file to be committed before assume-unchanged will remain visible to all users in the repo.

My questions:

  1. Is the above interpretation correct? Please correct me.

  2. If a file has already been in a commit, what is the functional different between matching it in .exclude and running assume-unchanged on it? Why would one prefer one approach to another?

  3. My basic use case is that I want to avoid sorting through diffs on compiled files, but I still want those compiled files synced along with the source files. Will a gitignore'd file still be pushed? If not, how to manage final deployment of the compiled files?

Supercharger answered 16/4, 2014 at 1:24 Comment(0)
S
141

I'm going to accept this emailed answer from Junio Hamano (the maintainer of Git) because I think it explains some things more lucidly than the official docs, and it can be taken as "official" advice:

The .gitignore and .git/info/exclude are the two UIs to invoke the same mechanism. In-tree .gitignore are to be shared among project members (i.e. everybody working on the project should consider the paths that match the ignore pattern in there as cruft). On the other hand, .git/info/exclude is meant for personal ignore patterns (i.e. you, while working on the project, consider them as cruft).

Assume-unchanged should not be abused for an ignore mechanism. It is, "I know my filesystem operations are slow. My intention is not to change these paths so I have Git mark them with the 'assume-unchanged' bit. So, Git will not check for changes in these paths every time I ask for 'git status' output". It does not mean anything other than that. Especially, Git does not promise to always consider that these paths are unmodified. If Git can determine any of these paths have changed without incurring extra lstat(2) cost, it reserves the right to mark them as modified. As a result, "git commit -a" will commit that change.

Supercharger answered 26/4, 2014 at 0:31 Comment(5)
" by making them with that bit---that way" ? what does that mean?Ave
@BlueClouds, there's a comma after "that way" as it's the start of a new thought. I suspect "making them with that bit" was intended to say "marking" and refers to the flag created by "assume unchanged" as a "bit"—I would imagine this marking only takes one bit of storage as it's a binary state. I admit this is partly guesswork, but I don't have difficulty understanding the answer so perhaps it will help you.Mackoff
@Mackoff I have to agree with BlueClouds: I struggle to understand what "bit---that" means, too. You probably know more about the internals of git so that you're able to fill in those blanks, but it's still a haphazard jumble of magic to many others, including me.Tchao
People, there was a typo in the work marking and it became "making". All it means is that there is some flag that git is keeping per file, and this flag can be set and reset with this plumbing command.Bezonian
Additionally, please note that this flag is kept in the index and its value will get lost after operations which reset your index. Please refer to (this)[https://mcmap.net/q/11287/-git-difference-between-39-assume-unchanged-39-and-39-skip-worktree-39] answer for a clearer informationBezonian
L
15

Adding to Junio Hamano's answer, Git 2.3.0 (February 2015) now removes from the gitignore documentation

To ignore uncommitted changes in a file that is already tracked, use 'git update-index --assume-unchanged'.

See commit 936d2c9 from Michael J Gruber (mjg):

gitignore.txt: do not suggest assume-unchanged

git-update-index --assume-unchanged was never meant to ignore changes to tracked files (only to spare some stats).
So do not suggest it as a means to achieve that.

Lynching answered 1/2, 2015 at 21:39 Comment(0)
W
7

Hopefully, not too many sources of information are using tracked, indexed and committed loosely, since they are all different and meaningful.

  • Indexed means that the file is in the git index. At some point in the past, someone has use git add or an equivalent command on the file. The file is tracked, and might also be committed.
  • Tracked means that git is watching the file for changes. Any committed file, or any file in the index is tracked.
  • Committed means that the file is in git's history. There is at least one checkpoint for this file; you can revert to any committed version of the file.

Now to the limit of my own knowledge. I'm not sure about this definition, but this is my understanding; happy to be corrected about this:

when an indexed file is committed, it is no longer in the index. The next time it is modified (or deleted), it is back in the index. The index is the sum of all tracked files that differ from what's committed.

The index is also called the cache, or the staging area.

On to your main question. .git/info/exclude is the same as .gitignore, just a lower precedence and not in the repository (so, not committed and shared). Neither affects already tracked files. Both affect files that are not currently tracked. Updating .gitignore after git add or git commit is too late; git already tracks the file, and .gitignore won't affect that.

Assume-unchanged affects only tracked files, and thus is completely separate to .gitignore. It can temporarily pretend that the file is untracked and ignored (but it doesn't have to and can also do nothing different from normal behaviour). As other answers mention, this is not used for ignoring changes to files, just for potentially avoiding file system operations on slow file systems.

Re: point 3: you should not add compiled files to git. Compile your files to a different directory that your source is in, and ignore that entire directory. Bundle your compiled files into a library and add it to an artifact repository, but don't put them in git.

Whose answered 16/4, 2014 at 1:40 Comment(0)
U
1

I think the difference of .gitignore and assume-unchanged are

  1. .gitignore can be shared with other people in the team but assume-unchanged has to be configured for each member individually.

  2. assume-unchanged are tracked files. It is very useful if a file has configuration information but can be modified by the team. If a file is set as assume-unchanged but changed by other people and pushed to the remote repository, git will remind when try to pull from the remote.

Underproof answered 9/7, 2014 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.