简体   繁体   中英

How do I keep png files in git without tracking them?

I have png files in my bitbucket repo that I need for my readme file. But since these are binary files, I'm getting an error when the sonar bitbucket plugin runs diff on them.

How can I keep the files without it getting tracked?

I ran git update-index --skip-worktree filename and then git status but the flag is not reflecting. It said -

Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean

Not sure if I need to remove the file from the repo and then add the skip worktree flag. Can someone please tell me what I'm doing wrong or if there's a better way of saving image files without running diff on them? Thank you.

The literal answer to your question in the subject line:

How do I keep png files in git without tracking them?

is simply "you don't". That's because in Git, a tracked file is a file that exists in Git's index .

Git's index is a crucial data structure that you must know about (Git's behavior is inexplicable otherwise). Its name is so generic, and so bad, that it has two other names: it's also called the staging area , or sometimes—rarely these days—the cache . These days you mostly see the term "cache" in some of the flags to some commands, such as git rm --cached or git diff --cached . But all three terms really refer to this same thing.

The index's functions are complicated and numerous but there are really just a few that you have to know about. The main one—which is also why people call it the staging area —is that it holds, at all times, copies of the files that will go into your next commit.

The word "copies" should perhaps be in quotes here, because what's in the index really is what will go into the next commit. Commits do store files, but they store them in a frozen, compressed, Git-ified, and de-duplicated-content form. This allows Git to store every file in every commit . The fact that a new commit mostly stores the same files as the previous commit, and that Git de-duplicates the contents of each file, means that the new "copies" of the file take no space. This is true for the "copies" in the index as well: they're pre-de-duplicated, so as long as they match the current commit, they take no space. 1 Other than this, though, they really do act like copies of each file.

In other words, Git has, at all times, three copies of each (committed) file that you're working on or with:

  • There is a frozen one, saved for all time, in the current commit . You can't change this one, and it's not in a format you could use for anything, but Git can read it.

  • There's a "copy" in Git's index, ready to go into the next commit. This copy starts out matching the committed copy (well, normally anyway).

    This index copy is in the frozen format , but it's not actually frozen. If you modify the work-tree copy, you must run git add to update the index copy too. 2

  • Last, there is, of course, an ordinary read/write copy of the file. This copy is in your working tree or work-tree . This is the one you can see and use and change, but it's actually not in Git at all . It's not the copy that's in the commit, and it's not the copy that's ready to go into the next commit either—which is why you have to git add the file if you change this work-tree copy.

When you run git commit , Git makes the new snapshot from whatever is in the index. Between the time you run git checkout and the time you run git commit , you can control what's in Git's index, using git add and/or git rm . So the copies of files that are in Git's index can change, or even get removed entirely. This affects the next commit, once you actually get around to running git commit . Until then, it just "stages" the updated file(s).

(The git status command works by running two comparisons:

  • The first comparison tells you what's different between the current commit and the index. Whatever is different is staged for commit .
  • The second comparison tells you what's different between the index and your work-tree. Whatever is different is not staged for commit .

Since there are three copies, this is how a file can be both staged and not-staged at the same time: the committed version, the index version, and the work-tree version are just all different versions.)

In any case, we get back to the definition of a tracked file: A tracked file is any file that is in your work-tree and in Git's index right now. An untracked file is a file that is in your work-tree right now, but not in Git's index right now. It got into Git's index because (a) it came out of a commit, and/or (b) you ran git add on it. It has to be in Git's index if it is to be in a new commit. If it's not in Git's index now, eg, because you used git rm on it, it won't be in the next commit. If you don't want it in that commit, that's fine; but if you do want it in that commit, you will need to put it back into Git's index.

I ran git update-index --skip-worktree filename ...

This, and its related --assume-unchanged variant, just set a special bit in the index entry for the file (which has to be in Git's index, so that there's room for the bit to be set). When the bit is set, Git will often—not always, but often— pretend that the work-tree copy of the file matches the index copy of the file. It will then leave the index copy alone. So if the index copy currently matches the current-commit copy, setting the bit makes sure that a future git add doesn't use the work-tree copy (or lack thereof) to update the index copy. The index copy just remains there, in the index, still matching the current commit.

(When you use git checkout or git switch to switch to a new and different commit, so that Git has to update the index copies of various files, Git will not obey the assume-unchanged or skip-worktree bits, and will normally complain and stop the commit-changing if changing the index copy will destroy any uncommitted work in your work-tree. But this is at least a little bit dangerous, because listing the file in .gitignore can give Git the right to destroy the work-tree copy.)


1 They take a little space to hold the file names , cache data, and whatever else Git finds useful in terms of making Git work and go fast. They also take some bytes—currently 20 bytes per file—to hold content hash IDs, which relates to Git's internal storage format. This means that an index listing a few thousand files takes a few thousand KiB to store. For instance, in a Git repository for Git, we find:

$ git ls-files | wc -l

says that there are 3865 files in the index, and ls -l on .git/index turns up an index size of 366964 (bytes). The index also stores headers and trailers and other items, so there's no guaranteed direct correlation here, but it usually averages out pretty much like this.

2 Technically, this git add compresses and de-duplicates the file's content immediately, and then updates the blob hash ID in the index. If the content is already in the repository elsewhere, the new ready-to-commit file is de-duplicated. If the content is new , it's now in the repository for the first time, ready to be committed.

Note that if you git add a file after removing it from your working tree, Git will remove the index copy at this point. The git add command really means make the index copy match the work-tree copy , and if the work-tree copy is gone, this means Git should remove the index copy to match.

Of course, if there's no index copy at all, Git will create a new index entry, compressing and de-duplicating the work-tree content as usual. The index now holds the file name, blob hash ID, and cache data, and the index copy now matches the work-tree copy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM