tags:

views:

683

answers:

4

I have a project with the following structure:

/.
  /src
    /project1
      /bin
      /obj
    /project2
      /bin
      /obj
  /tools
    /tool1
      /bin

What can I add to my .git/info/exclude to ignore all bin/obj directories under "src"? I don't want to explicitly specify each project name.

+2  A: 

I believe you should be able to add

src/*/bin/*

to .gitignore, and anything that matches the pattern will be ignored.

Kendall Helmstetter Gelner
Doesn't work for me with `1.7.0.2.msysgit.0`.
Drew Noakes
+4  A: 

Try adding these lines to your .gitignore file:

src/*/bin
src/*/obj
Lars Haugseth
It just works... Thank you :)
TAZ
Doesn't work for me with `1.7.0.2.msysgit.0`. I posted an answer that works for me.
Drew Noakes
@Drew: Your answer seems more handy since it matches all directories with less fuss, so I voted it up.That said, I don't know why this answer would not work for you since I am using this technique currently without issue. Perhaps your version of git is old?
Kendall Helmstetter Gelner
@Kendall, actually it's a new machine with a new build of git. What platform are you on? I'm running msysgit on Win7 x64.
Drew Noakes
On a mac, running git 1.7.0.3Since you're on windows it's probably the forward slashes, it probably needs you to use backslashes. On a Mac the normal path separator is a forward slash.
Kendall Helmstetter Gelner
+3  A: 

The most obvious way would be to add these to src/.gitignore :

obj/
bin/

This ignores any paths that are in a directory call obj, or a directory called bin from the src directory downwards.

Something like src/*/obj/ in a top-level .gitignore might not work if you have a jagged project hierarchy with some obj and bin directories futher down the tree.

Here's quick test shell script showing the ignore rule in action:

#!/bin/sh
mkdir src
mkdir tools

mkdir src/project1
mkdir src/project2
mkdir tools/tool1

mkdir src/project1/bin
mkdir src/project1/obj
mkdir src/project2/bin
mkdir src/project2/obj
mkdir tools/tool1/bin

touch testfile
touch src/testfile
touch tools/testfile
touch src/project1/testfile
touch src/project2/testfile
touch tools/tool1/testfile
touch src/project1/bin/testfile
touch src/project1/obj/testfile
touch src/project2/bin/testfile
touch src/project2/obj/testfile
touch tools/tool1/bin/testfile

git init

add_empty() { touch "$1" && git add "$1"; }

add_empty dummy
add_empty src/dummy
add_empty tools/dummy
add_empty src/project1/dummy
add_empty src/project2/dummy
add_empty tools/tool1/dummy

git status

printf 'obj/\nbin/\n' >src/.gitignore && git add src/.gitignore

git status

The untracked file section of the first status is:

# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       src/project1/bin/
#       src/project1/obj/
#       src/project1/testfile
#       src/project2/bin/
#       src/project2/obj/
#       src/project2/testfile
#       src/testfile
#       testfile
#       tools/testfile
#       tools/tool1/bin/
#       tools/tool1/testfile

And after adding the .gitignore file:

# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       src/project1/testfile
#       src/project2/testfile
#       src/testfile
#       testfile
#       tools/testfile
#       tools/tool1/bin/
#       tools/tool1/testfile

As a test to prove that git isn't ignoring files called obj and bin but is ignoring obj and bin directories further down the hierarchy after running this script:

#!/bin/sh
mkdir src/project3
touch src/project3/testfile && git add src/project3/testfile
touch src/project3/obj
touch src/project3/bin

mkdir src/subdir
mkdir src/subdir/proj
touch src/subdir/proj/testfile && git add src/subdir/proj/testfile
mkdir src/subdir/proj/obj
mkdir src/subdir/proj/bin
touch src/subdir/proj/obj/testfile
touch src/subdir/proj/bin/testfile

The new untracked files are:

# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       src/project1/testfile
#       src/project2/testfile
#       src/project3/bin
#       src/project3/obj
#       src/testfile
#       testfile
#       tools/testfile
#       tools/tool1/bin/
#       tools/tool1/testfile
Charles Bailey
I am not sure it would work for all depths. I had trouble with those patterns here: http://stackoverflow.com/questions/991801/git-ignores-and-maven-targets/991873#991873 (and check also the link in the comment of that answer)
VonC
If it doesn't, it's a bug. The slash means 'match as a directory only', after that it's treated as a pattern without a slash (trailing slash is removed), so just as a regular file glob and will match anywhere. I'm not sure where the '**' thing comes from as it's not a syntax that git supports.
Charles Bailey
Addendum, you specifically need a *leading* slash if you wan't to anchor the match from the current directory, but that's not the case here, we want it anywhere below a directory, not 'anchored' at a directory.
Charles Bailey
@Charles Thank you for your feedback. I will make further tests, not only for this question, but also for the the other two I linked about in my previous comment.
VonC
+2  A: 

The accepted answer didn't work for me.

> git --version
git version 1.7.0.2.msysgit.0

Seems that forward slashes don't work with msysgit in the .gitignore file. This works.

*\bin
*\obj

However that will match exclude any files called bin or obj too, which isn't likely to be a problem, except for when it is. The following gets around this (and yes, a forward slash works in this case):

bin/
obj/
*.user
*.suo

This matches files at different depths in the hierarchy beneath the folder in which the .gitignore file is placed. Note that the above didn't work when I included a prefix for a specific subfolder, so I placed this in my Source folder directly.

As a Visual Studio user (presumably the OP is too from bin/obj reference) it's also nice to exclude .user and .suo files.


From the gitignore specification:

Patterns have the following format:

  • A blank line matches no files, so it can serve as a separator for readability.

  • A line starting with # serves as a comment.

  • An optional prefix ! which negates the pattern; any matching file excluded by a previous pattern will become included again. If a negated pattern matches, this will override lower precedence patterns sources.

  • If the pattern ends with a slash, it is removed for the purpose of the following description, but it would only find a match with a directory. In other words, foo/ will match a directory foo and paths underneath it, but will not match a regular file or a symbolic link foo (this is consistent with the way how pathspec works in general in git).

  • If the pattern does not contain a slash /, git treats it as a shell glob pattern and checks for a match against the pathname relative to the location of the .gitignore file (relative to the toplevel of the work tree if not from a .gitignore file).

  • Otherwise, git treats the pattern as a shell glob suitable for consumption by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not match a / in the pathname. For example, "Documentation/*.html" matches "Documentation/git.html" but not "Documentation/ppc/ppc.html" or "tools/perf/Documentation/perf.html".

  • A leading slash matches the beginning of the pathname. For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".

Drew Noakes