Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git - how to include only certain files and dirs from the whole working tree?

Tags:

git

I am developing an extension for magento. There is a lot of files in working dir, but I need to include in git only those I added in extension. How can I define in .gitignore rules for this case?

I tried this - .gitignore:

*
!/app/etc/modules/Some_Ext.xml
!/app/code/local/Some/Ext/
!/app/designer/...
... - etc.

But when I try git status it shows only .gitignore itself.

When I replace asterisk with certain dirs it doesn't change anything. What is a proper way to achieve my goal?

like image 910
Taras Avatar asked Dec 15 '22 10:12

Taras


1 Answers

UPDATE:

There is an easier solution:

*
!*/
!/app/etc/modules/Some_Ext.xml
!/app/code/local/Some/Ext/
!/app/designer/...
... - etc.

The second line will include all directories again then following patterns can take effect.


Well, have explored the source code, I found the 'gitignore' mechanism is in some degree really tricky.

Some points summarized as below:

  1. Be careful to ignore a directory. Git searches untracked files in a recursive way, ignoring directory will cause git skip that directory and automatically ignores all files / subdirectories under that, even you have a "not"-pattern. So

    /app
    !/app/code/index.php
    

    won't save index.php, it will be ignored together with /app.

  2. Do your best, use *.xml/txt/conf/etc... instead. And it is a good idea that never use standalone * because it will ignore any directories, which may be not what you want.

  3. There is no priority but order. For a directory or file, git matches the path against to .gitignore line by line and use the last matched pattern. If the last matched pattern has a leading !, git will include the file/directory, otherwise will ignore it.

    So

    *.xml
    !/app/etcmodules/Some_Ext.xml
    

    will reserve the Some_Ext.xml but

    !/app/etcmodules/Some_Ext.xml
    *.xml
    

    will filter it out.

  4. Update git to version 1.8.2 may help. In 1.8.2, they add a command git check-ignore for debugging your .gitignore config.


I think a workflow of git add -A can explain more.

Suppose there is a repository like this.

.
├── a.conf
├── b
│   └── b.conf
└── c
    └── c1
        └── c2
            └── c.conf

And in .gitignore it is

*.conf
b/
!b/b.conf
!c/c1/c2/c.conf

When I run git add -A, git will

  1. scan the working directory, find there is one regular file a.conf and two directories b and c.
  2. notice that file a.conf matches *.conf in .gitignore, then ignore it.
  3. b is a directory but is excluded by pattern b/ in .gitignore, stop recursing into b.
  4. because b is excluded, b/b.conf has never been scanned. ( Although he is unexcluded in the third line of .gitignore )
  5. c is a directory and seems not bad, include it and continue to recursing into it.
  6. c/c1/c2/c.conf matches two patterns, but the last one determines the fate. Because the last matched pattern !c/c1/c2/c.conf has a leading !, c/c1/c2/c.conf will survive.

Here is the result of git add -A at my machine (Mac with git of version 1.8.2)

# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   .gitignore
#       new file:   c/c1/c2/c.conf
like image 70
dyng Avatar answered May 21 '23 07:05

dyng