Git commit uses regular expressions or globs? - regex

Is it possible to use regular expressions in, e.g., git commit ".*my_file.*" ?
I tried, and it seems to only interpret these as globs. I also tired a regex flag:
git commit -regex ".*my_file.*"`
Throws an error.
Does anyone know of a way to combine regular expressions with Git commands?

The best way I can think of to do this is using the find command. For example, if you want only python files:
find -type f -regex ".*\.py$" -exec git commit {} -m "committing only and all python files" \;
Can anyone else think of something less unwieldy?

Not with Git itself. Git just receives a list of files passed from the shell, so it would be up to your shell to do regular expression matching for files. I do not think bash can do this, but other shells may be able to.

As mentioned by mipadi, arguments can be generated by the shell to produce the input for git.
For example, ls can be used in combination for this. Let's say I've got a git init-ed directory with the following files:
.git/
my_new_project_file.py
my_older_project_file.py
some_other_file.py
And I want to add everything but some_other_file.py. To do this:
ls my*project*.py | xargs git add
Checking my git status will show that both my_new_project_file.py and my_older_project_file.py have been staged, while some_other_file.py has been ignored.
n.b. ls doesn't support regex; just globbing.

As pointed out by Candic3, git supports globs:
git add *my_file*

Related

Git Grep Multiple line Regex

I wrote a regex to find any file containing space Word [ and here is the regex.
^\s+Session\[
and I want to use this regex in git grep,
so I set up a file in my repo that matched the regex and runs it.
here is what I run
git grep '^\s+Word\[' -- '*.cs'
but it returns nothing. I'm really new to git and regex any reference or suggestion to solve this problem?
It looks like you are trying to use Perl regular expressions syntax with git grep. Just add -P (perl-regexp) option and it will work.
UPD: for those who comes here to find about multi line patterns to git grep (just like me): Git Grep Multiple Words on Multiple Lines

Search filenames with regex

Is there any way to do something like git log <path>, but instead of path using a regex? I want to search commits containing files, whose filenames match a given pattern...
... and while we're at it: Is there also a way to do a git status / git diff only for filenames matching a given pattern?
Thanks in advance!
EDIT: I would be terrific if any way to do it, would also work for Git v1.7.1.
As far as a pure git solution goes and I'm aware of the only option to match specific file patterns is to use a glob.
git log -- '*.json'
Will give you all files which contain changes to a json file. The same can be done for git status.
On the other hand it's quite easy to search for regular expressions in the diff or the commit message. git log offers a --grep option to search for matches in the commit message and a -S option to search for strings.
Take a look at this question for further details.
For a simple pattern you could try, for example:
find . -name "*.c" | xargs git log
For a full-blown regex you can use:
find . | grep "REGEX" | xargs git log
If you need previously deleted files to be included in the output, you can use
git log --all --pretty=format: --name-only --diff-filter=A | sort -u | grep "REGEX" | xargs git log --
The first part of the above command, which finds all files that were ever in git, was lifted from an answser to this other question.
Thanks to your answers (especially Greg and Michael) I developed a way myself. (I hope this proves viable):
git log --name-only --pretty="format:"|sort -u|egrep '<REGEX>'|xargs git log --
Can you do something like:
git log | grep [string_to_look_for]

Using two asterisks to add a file in git

I want to add a file which has a unique file name but a long preceding path (e.g. a/b/c/d/filename.java). Normally I would add this to my repository by doing
git add *filename.java.
However I have also done this before:
git add a/b/c/d/filename*
So I tried to combine the two:
git add *filename*
but this does something weird. It adds every untracked file. I can see possible reasons for failure but they all should occur in one of the previous two commands so I don't know why this is happening.
My question isn't so much about how to add a file to a git repository with just its file name (although that would be useful).
My question is what is my misunderstanding of the * operation which makes me think the above should work.
Info:
I am using Git Bash for Windows, which is based on minGW.
You're looking at globs
(not regular expressions, which are a different pattern-matching language), and they're expanded by your shell, not by git.
If you want to see how they're going to match, just pass the same glob to another command, eg.
$ ls -d *filename.java
vs
$ ls -d *filename*
(I've just added the -d so ls doesn't show the contents of any directories that match)
Since you're using git bash, and it's possible that glob expansion behaves differently from a regular shell, try
$ git add --dry-run --verbose -- *filename*
for example: this should show you how it really expands the glob and what effect that has.
Note the -- ... if you're using globs that might match a filename with a leading -, it's important to make sure git knows it's a filename and not an option.
Unfortunately, this will only show you the files which both match the glob, and have some difference between the index and working copy.
Answer from author:
The dry run helped a lot, here is what I found:
I was forgetting about the bin folder which I haven't added, so when I performed the dry run I realised it was finding two matches: filename.java and filename.class. When I changed the glob to *filename.j* it worked.
My next step was to remove the .class and try the command again: it worked! It is still unexplained why git bash added everything when it found two matches... since the dry run behaves differently from the actual run I think there must be a bug, but I think that discussion is to be held elsewhere (unless somebody thinks it isn't a bug).
You could try with git add ./**/*.java
Note: I tested with zsh, it should also work for bash as well.

inotifywait - exclude regex pattern formatting

I am trying to use inotifywait to watch all .js files under my ~/js directory; how do I format my regex inside the following command?
$ inotifywait -m -r --exclude [REGEX HERE] ~/js
The regex - according to the man page, should be of POSIX extended regular expression - needs to match "all files except those that ends in .js", so these files can in turn be excluded by the --exclude option.
I've tried the (?!) lookaround thing, but it doesn't seem to work in this case. Any ideas or workarounds? Would much appreciate your help on this issue.
I've tried the (?!) thing
This thing is called negative lookahead and it is not supported by POSIX ERE.
So you have to do it the hard way, i.e. match everything that you want to exclude.
e.g.
\.(txt|xml) etc.
inotifywait has no include option and POSIX extended regular expressions don't support negation. (Answered by FailedDev)
You can patch the inotify tools to get an --include option. But you need to compile and maintain it yourself. (Answered by browndav)
A quicker workaround is using grep.
$ inotifywait -m -r ~/js | grep '\.js$'
But be aware of grep's buffering if you pipe the output to another commands. Add --line-buffered to make it work with while read. Here is an example:
$ inotifywait -m -r ~/js | grep '\.js$' --line-buffered |
while read path events file; do
echo "$events happened to $file in $path"
done
If you just want to watch already existing files, you can also use find to generate the list of files. It will not watch newly created files.
$ find ~/js -name '*.js' | xargs inotifywait -m
If all your files are in one directory, you can also use ostrokach's suggestion. In that case shell expansion is much easier than find and xargs. But again, it won't watch newly created files.
$ inotifywait -m ~/js/*.js
I posted a patch here that adds --include and --includei options that work like negations of --exclude and --excludei:
https://github.com/browndav/inotify-tools/commit/160bc09c7b8e78493e55fc9f071d0c5575496429
Obviously you'd have to rebuild inotifytools, and this is relatively untested, but hopefully it can make it in to mainline or is helpful to someone who comes across this post later.
Make sure you are quoting the regex command, if you are using shell-relevant characters (including ()).
While this is working:
inotifywait --exclude \.pyc .
this is not:
inotifywait --exclude (\.pyc|~) .
You have to quote the entire regular expression:
inotifywait --exclude '.*(\.pyc|~)' .
As of version 3.20.1, inotifywait does include the --include and --includei options.
To see them, run inotifywait --help. For some reason, they aren't documented in the manpages.
You could get most of this with --exclude '\.[^j][^s]' to ignore files unless they contain .js at some point in the filename or path. If you combine it with -r then it will work with arbitrary levels of nesting.
Only drawback is filenames like test.js.old will still be watched and all files inside a directory called example.js/ will also be watched, but this is probably somewhat unlikely.
You could probably extend this regex to fix this but personally I don't think the drawbacks are a big enough of a deal to worry about.

script to add files to SVN with filters

My bash scripting is weak. I want to create a script that filters and add files to the svn.
So far i have this
ls | egrep -v "(\.tab\.|\.yy\.|\.o$|\.exe$|~$)"
I tried to output it using exec but couldnt figure out how. Before that I checked if svn add uses regex. I am not sure if it does and i couldnt figure out how to reverse the above without the -v (i tired "[^((\.tab\.|\.yy\.|\.o$|\.exe$|~$))]" but that didnt work as expected (it seems to only ignore .tab. files))
How do i create a script to add files to svn after applying a filter? Would this be the most simple way? -> use ls, grep, put into a bash array then use a foreach with an svn add $element ?
NOTE: This is using linux, i dont think i'll have this running on windows (i couldnt set up bison) so as long as it works on most linux distros i am happy. Ignore the fact the above uses .exe
A number of ways:
Use backticks: svn add ``ls | egrep stuff
Use xargs: ls | egrep stuff | xargs svn add
Use find and xargs: find . -type f -name *.c -print | grep -v '\.svn' | xargs svn add
Obviously, change "stuff" and the "-name *.c" to suit your requirements...
Try using find.
find <pattern> -prune .svn -exec svn add {} \;
The command following exec will be executed for each file and {} will be replaced with the filename at each iteration.
I'm not in front of my linux system so I can't get you a pattern that you need right now but if you read the man, you might get there.
Another solution to this is to add those file extensions and the .svn folder to your SVN ignore pattern.
Armed with a client configured as such, you could then do svn add * and get only what you want into SVN.