How can I pipe output from git log in Git Bash? - bash

Reason: I want to compare two arbitrary different commits using a difftool. I know the hashes from a search and I don't want to copy these hashes, thus I am looking for a command that does something like
$ log_str=$(git log --all -S"new_tour <-" --pretty=format:"%h")
$ git difftool -t kdiff3 log_str[1] log_str[2] myfile.txt
I would like to be able to address arbitrary indices - not always 1 and 2
It would be great if the answer also gives a hint, how to figure out, what the structure of log_str is. Is it a character? An array of characters? A list? ... using the Bash.
I found some related help here and here, but I can't make it work.
Now I do:
$ git log --pretty=format:"%h"
3f69dc7
b8242c6
01aa74f
903c5aa
069cfc5
and
$ git difftool -t kdiff3 3f69dc7 b8242c6 myfile.txt

I would take a two step approach using a temporary file:
git log --all -S'SEARCH' --pretty=format:"%h" > tmp_out
git diff "$(sed -n '1p' tmp_out)" "$(sed -n '2p' tmp_out)" myfile.txt
rm tmp_out
sed is used to display line 1 and line 2 of the file.
With variables:
search="foo"
index_a="1"
index_b="2"
file="myfile.txt"
git log --all -S"${search}" --pretty=format:"%h" > tmp_out
git diff "$(sed -n "${index_a}p" tmp_out)" "$(sed -n "${index_b}p" tmp_out)" "${file}"
rm tmp_out
in a bash function:
search_diff() {
search="${1}"
index_a="${2}"
index_b="${3}"
file="${4}"
git log --all -S"${search}" --pretty=format:"%h" > tmp_out
git diff "$(sed -n "${index_a}p" tmp_out)" "$(sed -n "${index_b}p" tmp_out)" "${file}"
rm tmp_out
}
search_diff "foo" 2 3 myfile.txt

Related

Find wrapped strings in a pre-push git hook

I am trying to go through the changes being made in a git push and find any instance of a wrapped string like so: ___('something to be translated') so that I can make some subsequent API calls with that information. But for some reason I am unable to get any sort of useful output when I try to use a git diff --cached call. I already have my regex pattern figured out to do the search. Any suggestions on this would be great.
My code looks something like this:
FILES_PATTERN="/___[^)]+\)/gm"
git diff --cached --name-only | \
grep -E $FILES_PATTERN | \
GREP_COLOR='4;5;37;41' xargs grep --color --with-filename -n echo 'COMMIT contains strings that need to be uploaded to Lokalise.' && exit 1
Try this. I think your bash script is the main issue. It's not formatted properly. This will also make it so the output will only be the modified lines in addition to the ___() matches.
pattern="___\([^)]+\)"
echo $(git diff $remote_sha $local_sha | grep -E $pattern | grep '^[+-]')
Hope this works.

How to properly do command substitution and concatenation in bash script and display output

I'm trying to split the following command to use it in a script:
git diff HEAD --name-only && git submodule foreach git diff HEAD --name-only | grep -v '^Entering')
So I've tried to do this:
GIT_CMD=$(git diff HEAD --name-only)
GIT_SUBMODULE_CMD=$(git submodule foreach git diff HEAD --name-only)
CMD="$GIT_CMD && $GIT_SUBMODULE_CMD | grep -v '^Entering'"
echo $CMD
and the output I get is:
<file names> | grep -v '^Entering'
$GIT_CMD && $GIT_SUBMODULE_CMD are executed but I don't know what to do with the "| grep" part.
Putting the command inside $() will execute the command and place the output in the variable.
Try:
GIT_CMD="git diff HEAD --name-only"
GIT_SUBMODULE_CMD="git submodule foreach git diff HEAD --name-only"
CMD="$GIT_CMD && $GIT_SUBMODULE_CMD | grep -v '^Entering'"
echo $CMD
Now you are just assigning the command to the variable and not the output of the command.

How to delete line from CSV as they are read in Bash

I am currently doing this:
while read l
do
echo git add $l/
git add $l/
# sed -i -e '1,1d' data/commit-folders.csv
# echo git commit -am "'Autocommit'"
# git commit -uno -am "'Autocommit'"
# echo git push origin master
# git push origin master
done < data/commit-folders.csv
Essentially just git add <folder> for a list of folders in a CSV file. I would like for this to be more robust, in that every time it restarts it restarts from where it left off. So I added that commented out line which does an in-place delete sed -i -e '1,1d' data/commit-folders.csv. However, with while read line, it messes up with the current line if they are being deleted. So I'm wondering how to do this properly.
How to iterate through a CSV file with <path> on each line, and delete the path once it is successfully git added. It seems like you need to have a loop that selects the first line from a file, and then deletes it from the file afterwards, rather than using while read line.
Here a solution without sed.
#!/bin/bash
csv="data/commit-folders.csv"
done="$(mktemp)"
# autoremove tempfile at exit
trap 'rm "$done"' EXIT
# loop over all lines in csv
while read -r file; do
printf "git add %s\n" "$file"
git add "$file"
# write processed files in tempfile
printf "%s\n" "$file" >> "$done"
#...
done < "$csv"
# create tempfile for merge result
newfile="$(mktemp)"
# sort: merge and sort $cvs with $done
# uniq -u: write only unique files into tempfile
sort "$csv" "$done" | uniq -u > "$newfile"
# override $csv with tempfile
mv "$newfile" "$csv"
you can use sed -i "/${l}/d" , it will find the exact line and delete it. This assumes that there would be no duplicate lines.
while read l
do
echo git add $l/
git add $l/
# sed -i -e '1,1d' data/commit-folders.csv
sed -i "/${l}/d" data/commit-folders.csv
# echo git commit -am "'Autocommit'"
# git commit -uno -am "'Autocommit'"
# echo git push origin master
# git push origin master
done < data/commit-folders.csv

Is there any way to type some text automatically on terminal?

When I use git via terminal I open a tab dedicated to git command only, then I don't want to type "git " every time. Is there any way to make some text automatically typed on every line?
You can define every git command as an alias, so that for example typing diff mybranch will invoke git diff mybranch. To invoke the normal shell command, type a backslash before it, for example \diff file ../elsewhere/file invokes /usr/bin/diff and not git diff.
Put the following code in a file ~/.git.bashrc. Configure your git terminal to run bash --rcfile ~/.git.bashrc instead of just running bash.
. ~/.bashrc
for c in $(COLUMNS=4 git help -a | sed -n 's/^ \([a-z]\)/\1/p';
git config --get-regexp '^alias.' | sed 's/alias\.//; s/ .*//')
do
alias "$c=git $c"
complete -F _complete_alias foo
done
The complete line requires the _complete_alias function.
I created this .bashrc function that pushes the code and tags it.
All you need to give it is the comment you want for the push.
The alias of the function is "gp" (which stands for git push).
So if you want to push and tag some code all you need after you add this code to your .bashrc is:
$ gp "test my new git push function"
gpfunction() {
git status
echo [Enter to continue...]
read a
git pull
git commit -am"$1"
git push
tag_major_min=$(git tag |sort -V|tail -1|awk -F. '{print $1 "." $2 "."}')
echo Tag major min $tag_major_min
latest_tag_number=$(git tag |sort -V|tail -1|awk -F. '{print $3}')
echo Latest tag number $latest_tag_number
next=$(echo $latest_tag_number + 1 | bc)
echo Next $next
new_tag=$(echo $tag_major_min $next | sed 's/ //g')
echo New tag $new_tag
git tag $new_tag
git push origin $new_tag
}
alias gp=gpfunction
This script uses a major.minor.patch version standard and increments the patch version.
You can tweak it as you please.

Makefile bash & xargs variables doesn't work

Here's a Makefile
roman#debian ~/D/O/devops> cat Makefile
install:
-cat projects.txt | xargs -n 2 bash -c 'git clone $0 $1'
Here's projects.txt
roman#debian ~/D/O/devops> cat projects.txt
git#github.com:xxx/xxx1.git app-xxx1
git#github.com:xxx/xxx2.git app-xxx2
Here's what happens when I just copy this command to bash - it works:
roman#debian ~/D/O/devops> cat projects.txt | xargs -n 2 bash -c 'git clone $0 $1'
fatal: destination path 'app-xxx1' already exists and is not an empty directory.
It's using git clone properly it's just repo exists.
Now when you do make install this fails, all variables are blank:
roman#debian ~/D/O/devops> make install
cat projects.txt | xargs -n 2 bash -c 'git clone '
You must specify a repository to clone.
I'd like to use only xargs method in here, else it becomes too wordy, also there's even more problems when using loops. I've also tried to use $(1) but no luck
make is interpreting $0 and $1 as make variables and trying to expand them. Try replacing $ with $$...
install:
-cat projects.txt | xargs -n 2 bash -c 'git clone $$0 $$1'
Use -I {} to read lines and use that for the input inside Makefile
install:
-cat projects.txt | xargs -I '{}' git clone '{}'
make expands dollar sign references to be its own variables. While it is usual to write $(name), it is possible to write $c where c is a single character (as long as it is not a $), so when you use $0 and $1 in your command line, they will be substituted with whatever values those variables have inside make. (make does not know anything about bash quoting, so $-references will be expanded anywhere in the line.)
Since make does not automatically define $0 and $1 and it is unlikely that you have defined them in your makefile, the most likely is that they will be substituted with the empty string, resulting in the error you observe. To avoid this problem, escape the dollar signs by doubling them:
-cat projects.txt | xargs -n 2 bash -c 'git clone $$0 $$1'
Having said that, it is not at all clear to me why you want to use bash -c here. What's wrong with
xargs -n2 git clone < projects.txt
Worked for me when I used two $.
$ cat Makefile
install:
cat projects.txt | xargs -n 2 bash -c 'echo git clone $$0 $$1'
$ make install
cat projects.txt | xargs -n 2 bash -c 'echo git clone $0 $1'
git clone git#github.com:xxx/xxx1.git app-xxx1
git clone git#github.com:xxx/xxx2.git app-xxx2

Resources