Git Extract modification in one string line - bash

Any good combination of Bash + git diff to get in one line the only change that I made in my file?
I'm using form Jenkins DSL, and the best that I get so far is this
"${sh(script: "git diff --shortstat", returnStdout: true)}".trim() == "1 file changed, 1 insertion(+), 1 deletion(-)"
But what I would love to have is the "hello world" text that I just add into one of the files.

If you've got just one hunk,
git diff -U0 | sed 1,/^##/d
and strip the leading character off.

Related

Pass the stdout of `git diff --name-only` to an executable file as parameters of the file

So, there's this executable file called pint (it's part of the Laravel 9 framework). It formats PHP files according to a configurable standard like PSR12.
Anyway, you can pass a list of the files you want to format as the parameters of pint like this:
pint file1 file2 file3 file4 ...
If you pass no argument, pint formats all files of the project.
So, what I'm trying to do is that I want pint to format only the files that have changed since the last commit. In other words, I want the output of git diff --name-only HEAD^ HEAD to be passed as parameters of pint in bash shell.
So, this is what I could come up with, but sadly it doesn't work:
git diff --name-only HEAD^ HEAD -o /dev/stdout | ./vendor/bin/pint
Which says: fatal: /dev/stdout: '/dev/stdout' is outside repository at '/home/user/directory' and then it proceeds to execute ./vendor/bin/pint normally as if no argument had been passed.
I suppose I should somehow convert new line to space before passing it to pint but I'm not sure.
| is for piping to standard input, but pint expects the filenames to be command-line arguments, not stdin.
Use $(...) to substitute the output of a command into the command line.
./vendor/bin/pint $(git diff --name-only HEAD^ HEAD)
Note that this won't work if any of the filenames contain whitespace, since the spaces will be treated as filename delimiters.

GIT: How to search through older versions of a file and list all versions that match the search criteria?

I have a repo that contains a certain file. I need to create a git script that searches through all the previous versions of this file and lists the commit SHAs that contain a specific string.
I want to have a list of all the commits that in their version that string exists.
The best answer I could find is here (but not good enough): https://stackoverflow.com/a/4705617/4441211
This solution is not good enough because this only finds where there was a change (i.e the search term was added or removed). Does anybody have a better idea how to do this?
To look for a pattern <pattern> in a file <path/to/file> within a commit <commit> : use git grep
git grep -e <pattern> <commit> -- <path/to/file>
Check git help grep for more details : many options are copied of the original grep command (-l to only list file names, -q to drop output ...)
If your intention is to scan all commits looking for a string (not just the commits where a change occured) :
git rev-list HEAD will give you the list of all commits in the ancestry of your active branch,
write a loop to repeatedly call git grep on these commits.
For example :
git rev-list HEAD | while read sha; do
git grep -q -e <pattern> $sha -- <path/to/file> && echo $sha
done

How to modify git log pretty format to strip out certain characters (like commas) from one of the fields?

I have a bash script that creates a CSV file with the git logs for a set of subdirectories across some repos, using git log's --pretty format to put each commit on one line with a few variables from my script as well as some of the built-in options.
The basic format of --pretty I'm using is as follows:
git log --pretty="$PWD,${current_dir},%h,%cs,%cN,%s"
Within the bash script, the full line looks like:
(git log --no-merges --after="${number_of_days} days ago" --pretty="$PWD,${current_dir},%h,%cs,%cN,%s" -- "$current_dir") >> "$starting_dir"/export.csv
Here's an example of what the CSV looks like:
/path/to/parent,./NameOfSubdirectory,bdacd7e,2021-03-24,kclemson,commit message,with,extra,commas,in it
/path/to/parent,./NameOfSubdirectory,45cb4a0,2021-03-24,kclemson,commit message foo
/path/to/parent,./NameOfSubdirectory,9f8294b,2021-03-24,kclemson,commit message bar
/path/to/parent,./NameOfSubdirectory,3e91e92,2021-03-24,kclemson,commit message baz
This works fine most of the time, but of course commas in the %s messes up the formatting when the CSV is opened in Excel. What I'd like to have it do instead is replace any commas in %s with a space, so it would look like this:
/path/to/parent,./NameOfSubdirectory,bdacd7e,2021-03-24,kclemson,commit message with extra commas in it
/path/to/parent,./NameOfSubdirectory,45cb4a0,2021-03-24,kclemson,commit message foo
/path/to/parent,./NameOfSubdirectory,9f8294b,2021-03-24,kclemson,commit message bar
/path/to/parent,./NameOfSubdirectory,3e91e92,2021-03-24,kclemson,commit message baz
What is the right way to do this? I assume I need to pass it to sed, but I'm looking for help on both the sed syntax to swap in a " " for a "," in that field, and also how to do that within the bash script.
Thanks.
Instead of , use some other delimiter that is unlikely to occur in the subject, like ^^^. Replace , with a white space first, and then replace ^^^ with ,.
git log --pretty="$PWD^^^${current_dir}^^^%h^^^%cs^^^%cN^^^%s" | \
sed -e 's/,/ /g' | sed -e 's/\^^^/,/g'

Output first line of temporary file

I am writing a script to checkout the latest git commit with the word "merge" inside the commit message. I am trying to output the latest git commit line to see if my script is working so far
tempfile=$((mktemp))
tempfile2=$((mktemp))
git log --oneline >> $tempfile
grep -i "merge" $tempfile | head -1 > $tempfile2
cat $tempfile2
I was expecting the script to output just one line containing "merge" however it outputs the whole log. I actually just want to take the commit id and git checkout the latest "merge" file to a detached head state. If anyone could help me with what to do next I would greatly appreciate it. Thank you

How can I use Git to identify function changes across different revisions of a repository?

I have a repository with a bunch of C files. Given the SHA hashes of two commits,
<commit-sha-1> and <commit-sha-2>,
I'd like to write a script (probably bash/ruby/python) that detects which functions in the C files in the repository have changed across these two commits.
I'm currently looking at the documentation for git log, git commit and git diff. If anyone has done something similar before, could you give me some pointers about where to start or how to proceed.
That doesn't look too good but you could combine git with your
favorite tagging system such as GNU global to achieve that. For
example:
#!/usr/bin/env sh
global -f main.c | awk '{print $NF}' | cut -d '(' -f1 | while read i
do
if [ $(git log -L:"$i":main.c HEAD^..HEAD | wc -l) -gt 0 ]
then
printf "%s() changed\n" "$i"
else
printf "%s() did not change\n" "$i"
fi
done
First, you need to create a database of functions in your project:
$ gtags .
Then run the above script to find functions in main.c that were
modified since the last commit. The script could of course be more
flexible, for example it could handle all *.c files changed between 2 commits as reported by git diff --stats.
Inside the script we use -L option of git log:
-L <start>,<end>:<file>, -L :<funcname>:<file>
Trace the evolution of the line range given by
"<start>,<end>" (or the function name regex <funcname>)
within the <file>. You may not give any pathspec
limiters. This is currently limited to a walk starting from
a single revision, i.e., you may only give zero or one
positive revision arguments. You can specify this option
more than once.
See this question.
Bash script:
#!/usr/bin/env bash
git diff | \
grep -E '^(##)' | \
grep '(' | \
sed 's/##.*##//' | \
sed 's/(.*//' | \
sed 's/\*//' | \
awk '{print $NF}' | \
uniq
Explanation:
1: Get diff
2: Get only lines with hunk headers; if the 'optional section heading' of a hunk header exists, it will be the function definition of a modified function
3: Pick only hunk headers containing open parentheses, as they will contain function definitions
4: Get rid of '## [old-file-range] [new-file-range] ##' sections in the lines
5: Get rid of everything after opening parentheses
6: Get rid of '*' from pointers
7: [See 'awk']: Print the last field (i.e: column) of the records (i.e: lines).
8: Get rid of duplicate names.

Resources