Skip to content

Added edit/remove functionality to git-ignore#1258

Merged
spacewander merged 13 commits into
tj:mainfrom
kdergachev:main
Jul 14, 2026
Merged

Added edit/remove functionality to git-ignore#1258
spacewander merged 13 commits into
tj:mainfrom
kdergachev:main

Conversation

@kdergachev

Copy link
Copy Markdown
Contributor

PR for issue #1257

These commits introduce flags -r/--remove and -e/--edit to git-ignore to allow removing patterns the same way they can be added and for opening ignore files in a text editor. Some other minor changes like '--' flag-argument separator introduced. New version is mostly backwards-compatible with old one.

Some quirks/things to consider:

  • Flags for actions/locations override each other and the last is the actual one.
  • Temporary file creation for remove (found that filling tmp file with double loop over lines and patterns is the best way to remove a list of patterns while not interpreting patterns as regex or any other type of special symbols, maybe there is a better way)
  • Should edit action create a file if one does not exist?
  • Unnecessary arguments are not checked for and just omitted

Submitting this as a draft, and if everything's OK/after changes are made will modify documentation accordingly (same for output with -h/--help flags).

@spacewander spacewander left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's update the docs, and completion script in https://github.com/tj/git-extras/tree/main/etc (if possible)

Comment thread bin/git-ignore Outdated
}

_usage() {
# TODO

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's either fulfill it or drop it

Comment thread bin/git-ignore Outdated
level="none"
action="none"
declare -a args
while [ "$1" != "" ]; do

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It breaks documented empty-string patterns. while [ "$1" != "" ] stops parsing as soon as a pattern is "", so existing examples like git ignore --local "" "# Temporary files" no longer add anything after the empty argument. Use while [ $# -gt 0 ] instead.

Comment thread bin/git-ignore Outdated
local file="${2/#~/$HOME}"
if [ -f "$file" ]; then
echo "Removing patterns from $1 gitignore ($2)..."
while read -r line; do

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can corrupt preserved lines during remove. read without IFS= trims leading/trailing whitespace, echo "$line" mishandles values like -n, and the loop skips a final line without a trailing newline. Use while IFS= read -r line || [ -n "$line" ]; do and printf '%s\n' "$line".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While thinking about these issues found that perl has \E \Q escapes. These could work too (something like perl -pe "s/\Q${pattern1}\E\n?//; s/\Q${pattern2}\E\n?//; ..."). Which of the approaches do you think is better?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we have to add perl in https://github.com/tj/git-extras/blob/main/Installation.md#dependencies. Could it be solved with awk or sed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I found a way to do that in awk and also keep echos saying what was dropped. Added it in 3e5076b.

Comment thread bin/git-ignore Outdated
edit_file() {
local file="${2/#~/$HOME}"
if [ -f "$file" ]; then
echo "Editing $1 gitignore ($2)..." && $(git var GIT_EDITOR) "$file"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$(git var GIT_EDITOR) "$file" loses shell quoting for editor values like vim -c 'set ft=gitignore', and echo "Done." still runs even if the editor exits non-zero.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the line to use eval - it seems to fix this issue.

Comment thread bin/git-ignore Outdated
tmpfile="$(mktemp -q "${TMPDIR:-/tmp}"/git-extras-ignore.XXXXXX 2>/dev/null)"
else
cd_to_git_root --warn &>/dev/null
tmpfile="$(mktemp -q "$GIT_DIR"/git-extras-ignore.XXXXXX 2>/dev/null)"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we always put the temp file in $TMPDIR?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted it to work the same way git does and it writes its tmp files in .git. Changed to always use global tmp directory.

Comment thread bin/git-ignore Outdated
echo "Removed $line pattern."
fi
done < "$file"
mv "$tmpfile" "$file" # tmp file created in get_tmp_file 'deleted'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If .gitignore or the global ignore file is a symlink, mv "$tmpfile" "$file" replaces the symlink instead of updating its target; it can also lose file metadata. Can we update it in place?

@spacewander spacewander left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM except one thing. Let's update usage and docs.

Comment thread bin/git-ignore
@kdergachev

Copy link
Copy Markdown
Contributor Author

Done

Comment thread bin/git-ignore Outdated
edit_file() {
local file="${2/#~/$HOME}"
if [ -f "$file" ]; then
echo "Editing $1 gitignore: ($2)" && eval "$(git var GIT_EDITOR) $file"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will spaces or shell metacharacters in the $file break the eval since we don't quote them?

@kdergachev kdergachev Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I guess so. The safest way to prevent that seems to be with $(printf '%q' "$file") (${file@Q} should work too, but for old versions of bash is unavailable). Should we do the same to the GIT_EDITOR part or is it assumed to be safe?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do it.

@kdergachev kdergachev Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it. Though left GIT_EDITOR part the same since I realized that it will then treat the whole string in that variable as the command, but GIT_EDITOR (I suppose) can contain flags or be even more complex than "<editor> <flags>..." (for example try eval " 'vim -e' ").

@spacewander spacewander left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. But could you exclude others' commits and fix the typo?

@kdergachev

Copy link
Copy Markdown
Contributor Author

Fixed.
Had to resort to resetting with a force-push and reapplying commits (made a mistake of pulling to local, adding commits, pushing to fork and only then syncing the fork).

@spacewander
spacewander merged commit b450b36 into tj:main Jul 14, 2026
6 checks passed
@spacewander

Copy link
Copy Markdown
Collaborator

@kdergachev
Merged. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants