2

For the docs of my repos I want to upload PDF's and UML diagrams (I guess as image files), but I don't want Git to track the changes. I just want to upload a file and when there is a new version of that file I want the old version to be replaced. So basically a file without versioning (I know this is not the sense of Git, but I just don't need it in this case).

Can this be done via Git or maybe in gitlab or github?

Mike van Dyke
  • 2,724
  • 3
  • 16
  • 31
  • 1
    `I just want to upload a file and when there is a new version of that file I want the old version to be replaced` That's what tracking changes means. – SLaks Jan 31 '18 at 21:14
  • @Slaks To me, it doesn't. Tracking changes would mean that I can see the changes that were made between the old version and the new version. And that's I want do not want/need. I just want the new version in my repository. – Mike van Dyke Jan 31 '18 at 21:32
  • Your problem here is that Git isn't about files, it's about commits. You want it to act as a file transport mechanism and it literally *can't* do that; it can only transport entire commits, which means you have history, because commits *are* history. You can, with sufficient force and/or external scripts, *bend* Git into doing what you want, but not via GitHub (maybe via GitLab, I have not used that). – torek Jan 31 '18 at 21:52
  • @torek hmm, that's what I suspected. – Mike van Dyke Jan 31 '18 at 22:04
  • @torek btw: please post an answer so I can accept it – Mike van Dyke Feb 09 '18 at 12:39

2 Answers2

3

It's not completely impossible to do this, but it goes against the way Git is designed, which makes it difficult.

The fundamental issue here is that Git is all about commits rather than files. A commit does contain files—in fact, each commit has a complete snapshot of every file1—and when you use Git as a transport mechanism, it transports whole commits. But a commit is also the unit of tracking; each commit normally has a link to one parent commit; and following these links is what gets you the history. In other words, the commits are the history, and having a file in a commit means that the file will be tracked.2

Ultimately, then, the two goals of having the file be untracked, yet still transported ("uploaded"), conflict with each other. To be transported, the file must be in a commit. If the file is in the commit, the file will be tracked the moment that commit gets checked-out.

To make all of this work, you would need to commit the file and transport the commit, then either forget the commit while keeping the file somewhere (git reset can do this), or else live with the commit existing and thus having the file tracked. When you want to update the file, you could make a new commit that has the side effect of discarding the old commit—e.g., using git commit --amend—and then send the new commit. But since the commit is a complete snapshot, and commits are history, discarding the old commit means discarding a piece of history. That's only OK if the only things in the commit are the PDFs and UML diagrams.

There is also a hybrid process: have one chain of commits that grows normally (normal history) that lacks the PDF and UML files, and a separate single, parentless commit—in the same or some other repository, but for the purpose of this answer, assume "same repository"—that stores the PDFs and UML diagrams only. To update the single-commit files, discard the old single parentless commit, creating a new single parentless commit. You can then have your Git send to some other Git both the normal history and the current single commit. You then have to arrange for the other Git to git checkout the normal history and extract the PDF-and-UML files into the work-tree of that other Git's repository, without putting those into the index.

Either of these methods—the one with a tricky commit-and-git reset, or the hybrid in which you keep a single root commit with the PDFs and UML files—requires a lot of fancy support on the server end. This is not, as far as I know, available via GitHub. If you control the server, it's always possible to write your own code to do it.


1More precisely, a commit has a snapshot of every file that is in the commit. But putting it like this makes it an obvious tautology: the commit contains that which the commit contains.

To see what's in any particular commit, run:

git ls-tree -r <hash-or-other-specifier>

2The precise definition of a tracked file is that it is any file that is in the index. This requires getting into what the index is; but we can note, here, without going into detail, that the index is populated from a commit. This means that if commit 1234567... stores file README, anything that extracts the commit leaves README in the index, so that it's tracked.

torek
  • 448,244
  • 59
  • 642
  • 775
0

Add it to a .gitignore file. Here's the documentation: https://git-scm.com/docs/gitignore

Bill
  • 61
  • 2
  • 11
  • If I gitignore a file, then it would not be uploaded, would it? – Mike van Dyke Jan 31 '18 at 21:35
  • For a whole bunch on what `.gitignore` means and why this isn't the answer here, see https://stackoverflow.com/q/48492043/1256452 – torek Jan 31 '18 at 21:50
  • Hmm maybe check the answer using git update-index here: https://stackoverflow.com/questions/9794931/keep-file-in-a-git-repo-but-dont-track-changes – Bill Jan 31 '18 at 21:50
  • Great description of .gitignore @torek. Thank you – Bill Jan 31 '18 at 21:54