How can binary files be ignored in git
using the .gitignore
file?
Example:
$ g++ hello.c -o hello
The "hello" file is a binary file. Can git
ignore this file ?
How can binary files be ignored in git
using the .gitignore
file?
Example:
$ g++ hello.c -o hello
The "hello" file is a binary file. Can git
ignore this file ?
# Ignore all
*
# Unignore all with extensions
!*.*
# Unignore all dirs
!*/
### Above combination will ignore all files without extension ###
# Ignore files with extension `.class` & `.sm`
*.class
*.sm
# Ignore `bin` dir
bin/
# or
*/bin/*
# Unignore all `.jar` in `bin` dir
!*/bin/*.jar
# Ignore all `library.jar` in `bin` dir
*/bin/library.jar
# Ignore a file with extension
relative/path/to/dir/filename.extension
# Ignore a file without extension
relative/path/to/dir/anotherfile
Add something like
*.o
in the .gitignore file and place it at the root of your repo ( or you can place in any sub directory you want - it will apply from that level on ) and check it in.
Edit:
For binaries with no extension, you are better off placing them in bin/
or some other folder. Afterall there is no ignore based on content-type.
You can try
*
!*.*
but that is not foolproof.
To append all executables to your .gitignore
(which you probably mean by "binary file" judging from your question), you can use
find . -executable -type f >>.gitignore
If you don't care about ordering of lines in your .gitignore
, you could also update your .gitignore
with the following command which also removes duplicates and keeps alphabetic ordering intact.
T=$(mktemp); (cat .gitignore; find . -executable -type f | sed -e 's%^\./%%') | sort | uniq >$T; mv $T .gitignore
Note, that you cannot pipe output directly to .gitignore
, because that would truncate the file before cat
opens it for reading. Also, you might want to add \! -regex '.*/.*/.*'
as an option to find if you do not want to include executable files in subdirectories.
Your best bet with binaries is to either give them an extension that you can easily filter out with a standard pattern, or put them into directories that you can filter out at the directory level.
The extension suggestion is more applicable in Windows, because extensions are standard and basically required, but in Unix, you may or may not use extensions on your executable binaries. In this case, you can put them in a bin/ folder, and add bin/
to your .gitignore.
In your very specific, small-scope example, you can just put hello
in your .gitignore.
You may try in your .gitignore
:
*
!*.c
This approach has many disadvantages, but it's acceptable for small projects.
If you're using a makefile, you could try modifying your make rules to append the names of new binaries to your .gitignore file.
Here's an example Makefile for a small Haskell project;
all: $(patsubst %.hs, %, $(wildcard *.hs))
%: %.hs
ghc $^
grep -xq "$@" .gitignore || echo $@ >> .gitignore
This makefile defines a rule for creating executables out of Haskell code. After ghc is invoked, we check the .gitignore to see if the binary is already in it. If it isn't, we append the name of the binary to the file.
Here's another solution using file. This way executable scripts will not end up in gitignore. You may need to change how the output from file is interpreted to match your system. One could then set up a pre-commit hook to call this script each time you commit.
import subprocess, os
git_root = subprocess.check_output(['git', 'root']).decode("UTF-8").strip()
exes = []
cut = len(git_root)
for root, dirnames, filenames in os.walk(git_root+"/src/"):
for fname in filenames:
f = os.path.join(root,fname)
if not os.access(f,os.X_OK):
continue
ft = subprocess.check_output(['file', f]).decode("UTF-8")
if 'ELF' in ft and 'executable' in ft:
exes.append(f[cut:])
gifiles = [ str.strip(a) for a in open(git_root + "/.gitignore").readlines() ]
gitignore=frozenset(exes+gifiles)
with open(git_root+"/.gitignore", "w") as g:
for a in sorted(gitignore):
print(a, file=g)
A way to also ignore in some subdir, not only in a root:
# Ignore everything in a root
/*
# But not files with extension located in a root
!/*.*
# And not my subdir (by name)
!/subdir/
# Ignore everything inside my subdir on any level below
/subdir/**/*
# A bit of magic, removing last slash or changing combination with previous line
# fails everything. Though very possibly it just says not to ignore sub-sub-dirs.
!/subdir/**/
# ...Also excluding (grand-)children files having extension on any level
# below subdir
!/subdir/**/*.*
Or, if you want to include only some specific types of files:
/*
!/*.c
!/*.h
!/subdir/
/subdir/**/*
!/subdir/**/
!/subdir/**/*.c
!/subdir/**/*.h
Seems it may even also work like for every new subdirectory if you want!:
/*
!/*.c
!/*.h
!/*/
/*/**/*
!/*/**/
!/*/**/*.c
!/*/**/*.h
Leading slashes are important only in first two lines and optional in other. Tailing slash in !/*/
and !/subdir/
is also optional, but only in this line.
I don't know any other solution but adding them one by one to .gitignore
.
A crude way to test is to grep the file command's output:
find . \( ! -regex '.*/\..*' \) -type f | xargs -n 1 file | egrep "ASCII|text"
EDIT
Why don't you simply name you executable hello.bin
?
Just add hello
or /hello
to your .gitignore. Either works.
Binary files are often without extensions. If this is your case try this:
*
!/**/
!*.*
REF: https://stackoverflow.com/a/19023985/1060487
I created a .gitignore file with two entries in GOPATH directory.
/bin
/pkg
It ignore all the compiled developments, currently.
.gitignore uses glob programming to filter files, at least on Linux.
I am about to give a coding talk at a Meetup and, in preparation, I made a directory with several subdirectories that are named according to the order I want to present them: 01_subject1, 02_subject2, 03_subject3. Each subdirectory contains a source file with a language-dependent extension that compiles to an executable file whose name matches the source file name without the extension according to common practice.
I exclude the compiled files in the numeral-prefixed directories with the following .gitignore line:
[0-9][0-9]_*/[!\.]*
According to my understanding of the documentation, it shouldn't work. Having the trailing asterisk should fail because it should match any number of unspecified characters, including the '.' + extension. Omitting the trailing asterisk should fail (and does) because [!\.]
matches only a single non-period character. However, I added the trailing asterisk, as I would for a regular expression, and it works. By work, I mean that git notices changes to the source file, but not the existence or changes to the compiled files.
Building on VenomVendors answer
# Ignore all
*
# Unignore all files with extensions recursively
!**/*.*
# Unignore Makefiles recursively
!**/Makefile
# other .gitignore rules...
Add the following to your .gitignore file:
[^\.]*
Explanation:
[] encloses a character class, e.g. [a-zA-Z] means "any letter".
^ means "not"
\. means a literal dot - without the backslash . means "any character"
* means "any number of these characters"
The .gitignore
mechanism works only based on file names, not on file contents. Being a binary file is a property of the content, hence you can't ask git ignore binary files directly, but only to ignore them by name (and as other suggested, you can either add all binary file names to your .gitignore
or use an appropriate naming convention).
The fact that .gitignore
works on file names is an important property performance-wise: Git only needs to list files, but not to open and read them to know which files to ignore. In other words, Git would be terribly slow if you could ask it to ignore files based on their contents.
Old thread, but still relevant.
I changed the makefile so the resulting binary file after linking has the name [filname].bin instead of only [filname]. Then I added *.bin files in the gitignore.
This routine fulfill my needs.