Last active
March 25, 2025 11:24
-
-
Save mdawaffe/529e6b3ee820e777c2cfd2f8255d187f to your computer and use it in GitHub Desktop.
Get line numbers of changed lines - git, diff - Full of bashisms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Call like you would `diff` | |
# `./diff-changed-lines.sh old new` | |
# Outputs the lines numbers of the new file | |
# that are not present in the old file. | |
# That is, outputs line numbers for new lines and changed lines | |
# and does not output line numbers deleted or unchanged lines. | |
args=( | |
# Don't output info for old (deleted) or unchanged (context) lines | |
--old-group-format="" --unchanged-group-format="" | |
# For new and changed lines, output one LINE_RANGE per line | |
--new-group-format="%dF-%dL%c'\012'" | |
--changed-group-format="%dF-%dL%c'\012'" | |
) | |
diff "${args[@]}" "$@" | while IFS=- read -r LINE END; do | |
for (( ; LINE <= END; LINE++ )); do | |
echo "$LINE" | |
done | |
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Call like you would for `git diff` | |
# `./git-diff-changed-lines` | |
# `./git-diff-changed-lines master...HEAD` | |
# `./git-diff-changed-lines branch1 branch2` | |
# etc. | |
# Outputs the lines numbers of the new file | |
# that are not present in the old file. | |
# That is, outputs line numbers for new lines and changed lines | |
# and does not output line numbers deleted or unchanged lines. | |
# FORMAT: One file per line | |
# FILE:LINE_NUMBERS | |
# Where LINE_NUMBERS is a comma separated list of line numbers | |
# https://stackoverflow.com/a/246128 | |
SOURCE="${BASH_SOURCE[0]}" | |
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink | |
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" | |
SOURCE="$(readlink "$SOURCE")" | |
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located | |
done | |
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" | |
git difftool --no-prompt --extcmd "$DIR/git-difftool-changed-lines.sh" "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Useful for `git difftool` | |
# `git difftool --extcmd=/path/to/git-difftool-changed-lines.sh` | |
# Outputs the lines numbers of the new file | |
# that are not present in the old file. | |
# That is, outputs line numbers for new lines and changed lines | |
# and does not output line numbers deleted or unchanged lines. | |
# FORMAT: One file per line | |
# FILE:LINE_NUMBERS | |
# Where LINE_NUMBERS is a comma separated list of line numbers | |
args=( | |
# Don't output info for old (deleted) or unchanged (context) lines | |
--old-group-format="" --unchanged-group-format="" | |
# For new and changed lines, output one LINE_RANGE per line | |
--new-group-format="%dF-%dL%c'\012'" | |
--changed-group-format="%dF-%dL%c'\012'" | |
) | |
# `git difftool` calls this command as `git-difftool.sh "$LOCAL" "$REMOTE" | |
# and adds BASE to the environment. | |
# See https://git-scm.com/docs/git-difftool#Documentation/git-difftool.txt--xltcommandgt | |
echo -n "$BASE:" | |
diff "${args[@]}" "$1" "$2" | while IFS=- read -r LINE END; do | |
echo -n "$(( LINE++ ))" | |
for (( ; LINE <= END; LINE++ )); do | |
echo -n ",$LINE" | |
done | |
echo | |
done |
I have a use-case where on CI I cross this output with the output from a linter, and fail the CI build if there are any lines that match. Given the output of my linter (rubocop), I need these bash scripts to output a filename with each line number on a separate line. To accomplish this, I made this change:
diff --git c/scripts/git-difftool-changed-lines.sh i/scripts/git-difftool-changed-lines.sh
index 174035ee..5e1f5210 100644
--- c/scripts/git-difftool-changed-lines.sh
+++ i/scripts/git-difftool-changed-lines.sh
@@ -27,12 +27,9 @@ args=(
# and adds BASE to the environment.
# See https://git-scm.com/docs/git-difftool#Documentation/git-difftool.txt--xltcommandgt
-echo -n "$BASE:"
-
diff "${args[@]}" "$1" "$2" | while IFS=- read -r LINE END; do
- echo -n "$(( LINE++ ))"
for (( ; LINE <= END; LINE++ )); do
- echo -n ",$LINE"
+ echo "$BASE:$LINE"
done
echo
done
can someone explain how does this work?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
macOS users: install GNU diff or else it won't work.