Hacker News new | ask | show | jobs
by p2e 5105 days ago
As someone new to git, I was dissapointed to see that:

    git add "*.txt"
added all of the .txt files from the current directory AND all of the .txt files contained within a subdirectory. I would have expected the same files to get added as those that would have shown up using:

    ls *.txt
For other new users: I've been told that this is an error in the tutorial. The tutorial forced the use of quotes but apparently they are not required and git would have added only the files that show up with the ls command as indicated above.

EDIT: I'm wrong. Using quotation marks DOES make git fetch .txt files within subdirectories. As pointed out by cellularmitosis, git seems to do it's own "interesting" glob expansion.

4 comments

Nice Find! I added it to my git-themed twitter account here: https://twitter.com/#!/gitHater

Let me explain what's happening.

What you are looking at is actually part-git, part unix-shell-y.

You did ls * .txt

Let's try something way crazy, type echo * .txt

What do you see? All of your txt files right? But that's just echo, not ls.

Ahh. Here's the clinch. When you do " * ", that's called either shell "expansion" or "globbing" depending on your shell. Basically, the shell says "ok, before I run your command, I'm going to look at it and see if I need to do anything on my end"

This is why you can do

   $ n=0
   $ echo $n
The shell hijacks your input, replacing "$n" with "0", then feeds it into echo

In your example, the shell has hijacked the star in "ls * .txt", replaced it with all of your txt files, say (a.txt, b.txt) and then ran ls.

That means that ls ACTUALLY got

   ls a.txt b.txt
And THAT's why it works with echo.

---------

So git add "* .txt" works differently, what gives?

Well, when you put things in double or single quotes you are telling the shell "hey, don't do your usual stuff here". The single quotes are more extreme. If we go back to our n=0 example we can try two more things:

   $ n=0
   $ echo $n
   $ echo "$n"
   $ echo '$n'
As you can see, the ' says "relax shell, I have this".

So when you do

    git add "* .txt" 
you are actually passing the "* .txt" to git.

In most reasonable, sensible programs, the program will look for a file named "asterisk dot t x t" in this case.

But alas, our friends at git have decided to be tricky. The ' * ' syntax for git is similar to gitignore-like syntax (http://www.kernel.org/pub/software/scm/git/docs/v1.7.10/giti...)

"Awesome", you exclaim! Not so fast. It's not the same.

So git add '!1' doesn't work. git add 'one/ * * ' doesn't work, only git add ' * ' seems to work.

Why is it so hard? Good question! I haven't any idea. But we can commiserate together ... you know, over twitter.

Have a good one!

It had you use `git add '* .txt'` because there were untracked txt files in the octofamily directory. `git add * .txt` would have just added the txt files in the root of the directory and ignored the octofamily directory.

I wouldn't think this is so much an error as they _want_ you to use '*.txt' to add the files in the subdirectory along with the files in the root. They could have touched better on the difference between quotes and no quotes though.

for those who aren't familiar with the nitty gritty, what's happening here is that bash (your shell) expands the "glob" (* .txt) before it ever runs ls, so what actually gets run isn't 'ls * .txt', it's 'ls foo.txt bar.txt dog.txt' etc.

but when you put quotes around "* .txt", that tells bash not to expand the glob.

so in the above case, '* .txt' is actually getting passed into git, rather than 'foo.txt bar.txt dog.txt' etc. I'm not a git user, but it sounds like git has special handling for "* .txt" which causes it to perform its own glob expansion, which happens to also include descending into directories. hilarity ensues.

EDIT: I can't seem to figure out how to type * .txt without triggering the italicized formatter, so I had to put a space after the asterisk. urgh.

I tried varying my commit messages from those recommended, (e.g., in the second commit, I typed 'git commit -m "Commit all the things!"'), and the commit messages weren't reflected in the "git log" output. It's not clear to me now how much of this is canned response and how much actually runs git.