How to redirect part of output of git subtree push - bash

git subtree push ... produces a lot of output. Although it is ok, using them on gitlab-ci is a nightmare.
I find it awful because the outputs are displayed line by line:
git push using: git#gitlab.xxx.com:micro/service.git feature/ci
1/207 (0)
2/207 (1)
3/207 (2)
4/207 (3)
5/207 (4)
6/207 (5)
7/207 (6)
8/207 (7)
...
Everything up-to-date
How can I hide 1/207 (0) without hiding the rest?
I tried
with the -q parameter, doesn't work
to pipe the output to a regex to "hide" the annoying lines:
$ git subtree push ... | while IFS= read -r line; do if [[ "$line" =~ [0-9]+/[0-9]+ ]];then : ; else echo "$line"; fi done doesn't work
?

You can try a grep to find and discard the line you don't want. But this is very specific to that query. Are you sure you don't want to hide some line class instead of just a string?
For your specific question, try
git subtree push ... | grep -v "1/207 (0)"
UPDATE:
Given the clarification, just adapt the search term and use regular expressions:
git subtree push ... | grep -v -e '[0-9]+/[0-9]+'

Related

Check if git branch contains commit with given subject

Given an exact subject line of a commit I want to know if a branch contains a commit with that subject.
What I have right now is: git log --format="%s" -F --grep="$msg" "$branch" | grep -Fq --max-count=1 -- "$msg"
I.e. search the log with a fixed-string grep and print the subject. Then search that subject with the same fixed-string and stop at the first match.
The 2nd grep is required because git log --grep may find the pattern anywhere in the commit message (e.g Fixes "$msg")
However this has the downside that it seemingly always walks the entire history of that branch which takes quite long.
As a test I ran git log --format="%s" -F --grep="$msg" "$branch" | grep -Fq --max-count=1 -- "$msg" and git log --format="%s" -F --grep="$msg" "$branch" and they both took the same time although the commit to grep for is found/printed very fast (for the 2nd)
So is there a way to directly find a commit in a branch by a given subject (using fixed strings as $msg comes from another command and may contain regex-like characters) faster or at least make my log-grep-pipe exit faster (on success)?
Try this:
git log --format="%s" "$branch" | grep -Fqx --max-count=1 -- "$msg"
Here x will match the entire line.. and max-count will return the first match.

why git log output redirect to a while loop not working?

I am trying this command in my bash shell script:
git log --oneline --no-decorate --pretty=format:"%s" $oldrev..$newrev
git log --oneline --no-decorate --pretty=format:"%s" $oldrev..$newrev | while read -r line; do
echo "$line"
done
the first git log can print output, but the second one followed by while won't print anything. why ?
I invoke my script like this:( second and third argument passed to $oldrev and $newrev)
./check master a735c2f eb23992
if I add --no-pager option, both will print nothing.
I am using bash 4.4.23(1)-release on fedora 28.
Instead of pretty=format, you should use pretty=tformat:
'tformat:'
The 'tformat:' format works exactly like 'format:', except that it provides "terminator" semantics instead of "separator" semantics.
In other words, each commit has the message terminator character (usually a newline) appended, rather than a separator placed between entries.
This means that the final entry of a single-line format will be properly terminated with a new line, just as the "oneline" format does. For example:
$ git log -2 --pretty=format:%h 4da45bef \
| perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
4da45be
7134973 -- NO NEWLINE
$ git log -2 --pretty=tformat:%h 4da45bef \
| perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
4da45be
7134973
In addition, any unrecognized string that has a % in it is interpreted as if it has tformat: in front of it.
For example, these two are equivalent:
$ git log -2 --pretty=tformat:%h 4da45bef
$ git log -2 --pretty=%h 4da45bef

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.

bash substring - combine command and slicing

I want to get first 8 characters of latest git commit hash. To retrieve git HEAD hash, I use git rev-parse HEAD. I've found here that I can get a substring using ${string:position:length}. But I don't know how to combine them both (in a one-liner, if possible). My attempt
${"`git rev-parse HEAD`":0:8}
is wrong.
You cannot combine BASH substring directive by calling a command inside it:
Instead you can use:
head=$(git rev-parse HEAD | cut -c1-8)
Or else old faishon 2 steps:
head=$(git rev-parse HEAD)
head=${head:0:8}
Using sed:
git rev-parse HEAD | sed 's/^\(.\{,8\}\).*$/\1/g'
out=`git rev-parse HEAD`
sub=${out:0:8}
example:
a="hello"
b=${a:0:3}
bash-3.2$ echo $b
hel
its a two step process, where first the output of git command is extracted, which is a string. ${string:pos:len will return the substring from pos of length len

Shell: How to delete mercurial files using an automated script?

I want to make a tiny script that deleted ALL the files in my Symfony project that mercuaril gives me as unwanted files.
For example:
hg status:
...
? web/images/lightwindow/._arrow-up.gif
? web/images/lightwindow/._black-70.png
? web/images/lightwindow/._black.png
? web/images/lightwindow/._nextlabel.gif
? web/images/lightwindow/._pattern_148-70.png
? web/images/lightwindow/._pattern_148.gif
? web/images/lightwindow/._prevlabel.gif
? web/js/._lightwindow.js
? web/sfPropel15Plugin
? web/sfProtoculousPlugin
I would like to delete all the files that are marked with the ?. ONLY THOSE. Not the ones modified -M-, and so on.
I'm trying to do a mini-script for that:
hg status | grep '^?*' | rm -f
I don't know if it is OK. Could you help me with one?
You're missing xargs, which takes the input and gives it to a command as parameters (right now you're actually sending them to rm's standard input, which isn't meaningful). Something like:
hg status | grep '^?' | cut -d' ' -f2 | xargs rm -f
Note: it won't work if your file names contain spaces. It'd still be possible but you need to be more clever.
Try this:
hg status|awk '/^? /{gsub(/^\? /, "", $0);print;}'|while read line; do
rm -f "$line"
done
The awk command matches everything starting with '?', and executes the block '{gsub(/^\? /, "", $0);print;}'. The block does a substitution on $0 (the entire line matched), replacing the starting "? " with nothing, making $0 just the filename. The print then prints $0 (print with no args defaults to printing $0)
So the awk output prints a list of filenames, one per line. This is fed into a read loop, which removes each.
This will preserve whitespace in filenames, but it will break if there are any filenames that contain newlines! Handling newlines gracefully is impossible with hg status as the input, since hg status prints newline-separated output

Resources