Skip to content

Adding git-ignore command, tests, and documentation. #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
/git-http-backend
/git-http-fetch
/git-http-push
/git-ignore
/git-imap-send
/git-index-pack
/git-init
Expand Down
116 changes: 116 additions & 0 deletions Documentation/git-ignore.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
git-ignore(1)
=============

NAME
----
git-ignore - Easily add entries to your .gitignore file


SYNOPSIS
--------
[verse]
'git ignore' [--dry-run | -n] [--ext | -e] [--all-ext | -E] [--dir | -d]
[--all-file | -a] [--parent-level | -p <parent_level>] pathspec [...]
'git ignore' --edit [--parent-level | -p <parent_level>]


DESCRIPTION
-----------
The command modifies a .gitignore file in your path easily. By default,
it adds lines to the .gitignore found in the root of your repository. It
can, however, add lines to a gitignore anywhere inbetween the file(s)
passed in and the root directory. The lines added can be based on
filename, extension, directory, or recursive glob.

Also, you can easily open the gitignore file using the $EDITOR environment
variable.


OPTIONS
-------
<pathspec>...::
Files to add to a gitignore. Fileglobs (e.g. `*.c`) can
be given to add all matching files. Also a
directory name can be given to add it to the gitignore
as well.

--edit::
Open the appropriate gitignore file in your default editor (using the
$EDITOR variable). This option can be combined with `--parent-level` based
on your current working directory.

-n::
--dry-run::
Don't actually edit the gitignore(s), just show what changes
would have taken place.

-e::
--ext::
Add the relative filepath based on extension. If pathspec
references path/to/file.log, the added gitignore line would
be path/to/*.log.

-E::
--all-ext::
Add a global exclusion of the given extension. If pathspec
references path/to/file.log, the added gitignore line would
be **/*.log.

-d::
--dir::
Add the contents of the parent directory. If pathspec references
path/to/file.log, the added gitignore line would be path/to/*.

-a::
--all-file::
Add a global exclusion of the given filename. If pathspec references
path/to/file.log, the added gitignore line would be **/file.log.

-p::
--parent-level <parent_level>::
Modifications will go to a gitignore located <parent_level>
directories above each of the files passed in. If the number
of parent levels causes the directory to fall outside of the
root of the git repository, a warning is printed and the root
of the repository is used instead. Using a parent-level of 0
will use the gitignore in the directory of each file passed in.

+
Note that the parent level is calculated for each file passed in. If multiple
files are passed in that have different parents at a given parent level, then
they will cause separate gitignore files to be written.


EXAMPLES
--------

* Adds all `*.log` files under `tmp` directory
and its subdirectories to the gitignore file found at the
root of the repository:
+
------------
$ pwd
/user/test/git_repo/src
$ git ignore -e tmp/file.log
------------
+
Results in `tmp/*.log` added to /user/test/git_repo/.gitignore


* Add the files under the `var/uploaded` directory to the gitignore above

+
------------
$ pwd
/user/test/git_repo/
$ git ignore -d --parent-level=1 www/var/uploaded/\*
------------
Results in `var/uploaded/*` added to /user/test/git_repo/www/.gitignore

SEE ALSO
--------
linkgit:gitignore[5]

GIT
---
Part of the linkgit:git[1] suite
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ TEST_PROGRAMS_NEED_X =
unexport CDPATH

SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-ignore.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-merge-octopus.sh
Expand Down
222 changes: 222 additions & 0 deletions git-ignore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
#!/bin/sh
#
# Copyright (c) 2016, Thurston Stone
#
# unit test: t7900

test -z "$DDDEBUG" || set -x

_verbose=0

SUBDIRECTORY_OK=Yes
OPTIONS_KEEPDASHDASH=
OPTIONS_STUCKLONG=t
# Would be nice to have examples, but rev-parse sees '*' as a symbol to hide everything afterwards
#e,ext add relative path for any file of that type (ex. path/to/*.ext)
#E,all-ext all files of that extention anywhere (ex. **/*.ext)
#d,dir all files under the parent directory (ex. directory/*)
#a,all-file all files of that file name (ex. **/filename.ext)
OPTIONS_SPEC="git ignore [options] [file|glob ...]
--
Miscelleneous
edit open the pertinent gitignore with your default text editor (Requires \$EDITOR to be set)
v,verbose show verbose output
n,dry-run do not actually edit any .gitignore files
Determine what files to add to the gitignore(s):
e,ext add relative path for any file of that type
E,all-ext all files of that extention anywhere
d,dir all files under the parent directory
a,all-file all files of that file name
Determine what gitignore(s) to use:
p,parent-level= number of parent directories containing the gitignore to edit. Set to 0 to put it in the local directory"

. git-sh-setup
. git-sh-i18n

write_output () {
if test $_verbose -eq 1
then
say $1
fi
}

get_git_ignore () {
directory=$1

# if we don't yet have the repo root directory, get it
if test -z "$repo_root"
then
#First, determine the root of the repository
repo_root="$(git rev-parse --show-toplevel)/"
write_output "repo_root=$repo_root"
fi

# get the path relative to the repo root
rel_directory="${directory#$repo_root}"
# if the relative path is the same as it was, try converting it to aa *nix
# style path
if test "$rel_directory" = "$directory"
then
# repo root 2 (cygwin-ified path) didn't work
# try the other one
write_output "changing repo_root from $repo_root"
#On windows, this turns to C:\... instead of /c/... from some other commands
repo_root=$(printf "$repo_root" | awk -F":" '{ if ($2) print "/" tolower($1) $2; else print $1 }')
write_output " to $repo_root"
rel_directory="${directory#$repo_root}"
fi
# default gitignore
gitignore="${repo_root}.gitignore"

# ------------------------------------------------
# Determine the correct git ignore and the path of
# the file relative to it
# ------------------------------------------------
if test $_parent_level -ge 0
then
parent=${directory}
write_output "parent=${parent}"

if test $_parent_level -ne 0
then
i=1
while test "$i" -le $_parent_level
do
parent="$(dirname "$parent")/"
write_output "parent=${parent}"
i=$(($i + 1))
done
fi
root_len=$(printf "${repo_root}" | wc -m)
parent_len=$(printf "${parent}" | wc -m)
if test $root_len -ge $parent_len
then
write_output "root_len(${root_len}) >= parent_len(${parent_len})...
uh-oh"
gettextln "WARNING: Parent directory is outside of the repository"
parent="${repo_root}"
else
write_output "root_len(${root_len}) < parent_len(${parent_len})...
good"
fi
rel_directory="${directory#$parent}"
gitignore="${parent}.gitignore"
fi

write_output "rel_directory=${rel_directory}"
write_output "gitignore=${gitignore}"

}

add_ignore () {
# get the absolute path of the file
file="$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
write_output "file=$file"

directory="$(dirname "$file")/"
write_output "directory=$directory"
get_git_ignore "$directory"

filename=$(basename "$file")
write_output "filename=$filename"
extension="${filename##*.}"
write_output "extension=$extension"
# defaault line
line="${rel_directory}${filename}"

# ------------------------------------------------
# Determine the correct line to add to the gitignore
# based on user inputs
# ------------------------------------------------
if test $_ext -eq 1
then
line="${rel_directory}*.$extension"
fi
if test $_directory -eq 1
then
line="${rel_directory}*"
fi
if test $_file_anywhere -eq 1
then
line="**/$filename"
fi
if test $_ext_anywhere -eq 1
then
line="**/*.$extension"
fi
write_output "line=${line}"
dryrun=""
if test $_dry_run -eq 1
then
dryrun="$(gettext "DRY-RUN!")"
fi
say "$dryrun $(eval_gettext "Adding \$line to \$gitignore")"
if test $_dry_run -eq 0
then
echo "$line" >>"$gitignore"
fi
}

_ext=0
_directory=0
_file_anywhere=0
_ext_anywhere=0
_parent_level=-1
_edit=0
_dry_run=0

while test $# != 0
do
case "$1" in
--ext)
_ext=1
;;
--all-ext)
_ext_anywhere=1
;;
--dir)
_directory=1
;;
--all-file)
_file_anywhere=1
;;
--parent-level=*)
_parent_level="${1#--parent-level=}"
if ! echo $_parent_level | grep -q '^[0-9]\+$'
then
gettextln "ILLEGAL PARAMETER: -p|--parent-level requires a numerical argument"
usage
fi
;;
--dry-run)
_dry_run=1
;;
--edit)
if test -z $EDITOR
then
gettextln "ERROR: Shell variable \$EDITOR must be set"
usage
fi
_edit=1
;;
--verbose)
_verbose=1
;;
--)
only_files_left=1
;;
*)
if test $only_files_left -eq 1
then
add_ignore "$1"
fi
;;
esac
shift
done
if test $_edit -eq 1
then
get_git_ignore "$(pwd)/"
git_editor "$gitignore"
fi
exit 0
Loading