I need to search for text "TEXT" in past 20 git commits (or range)
I need to see filename and line number where I have a match.
Note:
I want to search commits content, but not project on that commit as git grep
does.
By commits content I mean what I can see using git diff HEAD^^^..HEAD
Closest I got is using git log --raw -GTEXT
, it shows me commit which contains "TEXT" in commit content and show file names. Still no line numbers however.
And with some piping
git diff $(git log -n 20 --pretty=format:%h -GTEXT) | grep -E 'TEXT|\+\+\+|@@\s'
It is still somewhat wordy and with a lot of noise, if you have better solution, please answer.
Git Grep. Git ships with a command called grep that allows you to easily search through any committed tree, the working directory, or even the index for a string or regular expression. For the examples that follow, we'll search through the source code for Git itself.
To find out which files changed in a given commit, use the git log --raw command. It's the fastest and simplest way to get insight into which files a commit affects.
On Linux you can use gitk for this. It can be installed using "sudo apt-get install git-gui gitk". It can be used to see commits of a specific file by "gitk <Filename>".
Get the last 20 commits:
git log -n 20
Get each to an associative array:
declare -A COMMITS # Declare associative array
COMMITNUMBER=0
while read -r line; do # For each line, do
# Add 1 to COMMITNUMBER, if the current line contains "commit [0-9a-f]* (e.g., new associative array index for each commit)
# As this'll happen straight way, our array is technically 1-indexed (starts from "${COMMITS[1]}", not "${COMMITS[0]}")
REGEX="commit\s[0-9a-f]*"
[[ "$line" =~ $REGEX ]] && COMMITNUMBER=$(( COMMITNUMBER+1 ))
# Append the commit line to the index
COMMITS[$COMMITNUMBER]="${COMMITS[$COMMITNUMBER]} $line"
done < <(git log -n 20)
Then iterate:
for i in "${!COMMITS[@]}"
do
echo "key : $i"
echo "value: ${COMMITS[$i]}"
done
This gives similar output to below:
key : 1
value: commit 778f88ec8ad4f454aa5085cd0c8d51441668207c Author: Nick <[email protected]> Date: Sun Aug 7 11:43:24 2016 +0100 Second commit
key : 2
value: commit a38cd7b2310038af180a548c03b086717d205a61 Author: Nick <[email protected]> Date: Sun Aug 7 11:25:31 2016 +0100 Some commit
Now you can search each in the loop using grep
or anything, and match what you need:
for i in "${!COMMITS[@]}"
do
REGEX="Date:[\s]*Sun\sAug\7"
if [[ "${COMMITS[$i]}" =~ $REGEX ]]; then
echo "The following commit matched '$REGEX':"
echo "${COMMITS[$i]}"
fi
done
Altogether:
search_last_commits() {
[[ -z "$1" ]] && echo "Arg #1: No search pattern specified" && return 1
[[ -z "$2" ]] && echo "Arg #2: Number required for number of commits to return" && return 1
declare -A COMMITS # Declare associative array
COMMITNUMBER=0
while read -r line; do # For each line, do
# Add 1 to COMMITNUMBER, if the current line contains "commit [0-9a-f]* (e.g., new associative array index for each commit)
# As this'll happen straight way, our array is technically 1-indexed (starts from "${COMMITS[1]}", not "${COMMITS[0]}")
REGEX="commit\s[0-9a-f]*"
[[ "$line" =~ $REGEX ]] && COMMITNUMBER=$(( COMMITNUMBER+1 ))
# Append the commit line to the index
COMMITS[$COMMITNUMBER]="${COMMITS[$COMMITNUMBER]} $line"
done < <(git log -n $2)
for i in "${!COMMITS[@]}"
do
REGEX="$1"
if [[ "${COMMITS[$i]}" =~ $REGEX ]]; then
echo "The following commit matched '$REGEX':"
echo "${COMMITS[$i]}"
fi
done
}
EDIT:
Usage:
search_last_commits <search-term> <last-commits-quantity>
Example:
search_last_commits "Aug" 20
If you want to search through modified files in the range (and don't care about matching lines of the files that weren't actually modified in those commits) you can run:
git grep TEXT -- $(git diff --name-only RANGE)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With