qkhhly
qkhhly

Reputation: 1220

how to config git to overwrite non text file instead of version controlled it?

If I have a git repository that has both source code and other types of file, such slides, binary, etc. I want git to just version control the text file ( such as source code ). For other file types (binaries, for example), I just want to store one copy in the git repository, i.e. I want git to overwrite the file whenever I update it. I don't want to store multiple version for other types of file as they may be very large. Is there a way to config git for that purpose ? I run my own git host.

Thanks in advance!

Upvotes: 5

Views: 1543

Answers (2)

c00kiemon5ter
c00kiemon5ter

Reputation: 17674

add and commit all files you want to store in the repo once in a separate commit.
first commit should be of a file you want to keep track of (ie the text file).

each time you change a file which you want to keep track of, you make a new commit like you normally do.
each time you change a file which you want to be stored once, you make a new commit and rebase/fixup the commit to the commit that added the binaries.


here is the idea in practice:

$ ls
banana.pdf  bar.bin  foo.txt  mew.ppt

$ git status -s
?? banana.pdf
?? bar.bin
?? foo.txt
?? mew.ppt

add files - first the files to keep track of then all the binaries

$ git add foo.txt
$ git commit -m "foo text file"

$ git tag "root" HEAD   # easy access to the first commit

$ git add banana.pdf bar.bin mew.ppt
$ git commit -m "binaries"

make changes and commits

$ echo "ohai, I'm a change :D" >> foo.txt
$ git add foo.txt
$ git commit -m "foo changed"

$ echo "ohai, I'm a banana" | hexdump >> banana.pdf
$ git add banana.pdf
$ git commit -m "fixup! binaries"

lets look at what we have

$ git log --oneline
42c09bd fixup! binaries     # this will be merge with
a9b1853 foo changed
8899046 binaries            # this - same commit message!
7c8ae05 foo text file       # this is also the 'root' tag

now rebase the commits to fixup the commits for the binaries

$ git rebase --autosquash -i root    # everything will be ready for us
pick 8899046 binaries
fixup 42c09bd fixup! binaries        # notice this :)
pick a9b1853 foo changed
:wq                                  # vim save and quit

$ git log --oneline                  # lets look at what we end up with
41e1f09 foo changed
50adb90 binaries
7c8ae05 foo text file

it is very important to mark the new commit for the "non-tracked" file as

git commit -m "fixup! <same message as the commit to merge with>"

in our case the original message of the commit that added the 'banana.pdf' was binaries
so the commit message for the commit that changed any of the binaries should be fixup! binaries (as it is in the example)


if you do not name the commit that way then --autosquash cannot help you, and you have to manually move the line of the commit you want to change under the commit you want it to be merged with, and replace 'pick' with 'fixup', for example (continuing from where we left):

$ echo "ohai, more changes" >> bar.bin
$ git add bar.bin
$ git commit -m "changed bar"
$ git log --oneline
bd36eb9 changed bar
41e1f09 foo changed
50adb90 binaries
7c8ae05 foo text file

$ git rebase -i root
pick 50adb90 binaries      # you want this to merge with
pick 41e1f09 foo changed
pick bd36eb9 changed bar   # this

so change it to

pick 50adb90 binaries
fixup bd36eb9 changed bar  # under the line to be merged with and with 'fixup' instead of 'pick'
pick 41e1f09 foo changed
:wq                        # save and quit

$ git log --oneline        # what we end up with
9f94cbe foo changed
886eebd binaries
7c8ae05 foo text file

done :)


if you want to go further you can automate this with a git hook. see

$ git help githooks

a pre-commit hook would do the work for you with some tricks

Upvotes: 3

Philip Oakley
Philip Oakley

Reputation: 14101

Git, being a snapshot based VCS, with a cryptographically secure hash across the history, is not able to 'forget' an old version and replace it with a 'new' version of a file. This would break its crypto security.

Git is designed to be optimal for source code, and isn't optimal for binary files, but then neither are other VCS systems.

One solution is to ignore your binary files for the git repo, but create an alias for the git commit that will detect the binary file change and replace a copy in your separate archive, assuming its that important.

Do remember that if your binary files do not change very often then git is efficient about first, not storing duplicates, and second compressing those files. You can also mark the files as --assume-unchanged (i've not used it so check the manual) so that short-term changes are ignored.

Upvotes: 2

Related Questions