How to iterate among branches in git using BASH? - bash

I am pretty new in Bash. On git, I have branches named like following (YYcwXX):
version/21cw22
version/21cw23
version/21cw24
version/20cw35
master
I want to iterate among them and store the one which has the latest current week number - e.g 21cw24 in a variable.

I'd use git branch to list the relevant branches, sort them, and use tail to take the last. Then, I'd just trim away whitespaces and store in a variable:
export MY_BRANCH=`git branch | grep 'version/' | sort | tail -1 | tr -d ' '`

Related

Bash - how to copy latest files by filename to another folder?

Let's say I have these files in folder Test1
AAAA-12_21_2020.txt
AAAA-12_20_2020.txt
AAAA-12_19_2020.txt
BBB-12_21_2020.txt
BBB-12_20_2020.txt
BBB-12_19_2020.txt
I want below latest files to folder Test2
AAAA-12_21_2020.txt
BBB-12_21_2020.txt
This code would work:
ls $1 -U | sort | cut -f 1 -d "-" | uniq | while read -r prefix; do
ls $1/$prefix-* | sort -t '_' -k3,3V -k1,1V -k2,2V | head -n 1
done
We first iterate over every prefix in the directory specified as the first argument, which we get by sorting the list of files and deleting duplicates, before extracting everything before -. Then we sort those filenames by three fields separated by the _ symbol using the -k option of sort (primarily by years in the third field, then months in second and lastly days). We use version sort to be able to ignore the text around and interpret numbers correctly (as opposed to lexicographical sort).
I'm not sure whether this is the best way to do this, as I used only basic bash functions. Because of the date format and the fact that you have to differentiate prefixes, you have to parse the string fully, which is a job better suited for AWK or Perl.
Nonetheless, I would suggest using day-month-year or year-month-day format for machine-readable filenames.
Using awk:
ls -1 Test1/ | awk -v src_dir="Test1" -v target_dir="Test2" -F '(-|_)' '{p=$4""$2""$3; if(!($1 in b) || b[$1] < p){a[$1]=$0}} END {for (i in a) {system ("mv "src_dir"/"a[i]" "target_dir"/")}}'

To list the branch names based on branchtype

I have git branches under the type feature ad release i want to display the release branches when i give the input as release or the possible string(re, rel..etc) same as to feature branch and other branch types as well. I have a command to give the branch type now after when i get the branch type as release or feature based on my input i want to display the branch names under that type i choose.
Command I have:
#!/bin/bash
read branchtype
git branch --remote --list origin/* | grep $branchtype | cut -d '/' -f2 | sort -u
#!/bin/bash
read branchtype
git branch --remote --list origin/* | grep $branchtype | cut -d '/' -f2 | sort -u
First, I think you will have a much easier time if you use arguments to the script rather than reading stdin.
Second, why use a global pattern (origin/*) to return everything just to filter with a separate program (grep)?
Finally, maybe I misunderstand, but I imagine branch names like origin/feature/newThing and origin/feature/coolUpgrade and origin/bugfix/oopsie. Selecting for feature, that cut -d '/' -f2 | sort -u is just going to spit out feature and nothing else. (maybe you wanted -f3?)
Try this:
(create the file ~/bin/branchFilter first...)
$: cat ~/bin/branchFilter
#!/bin/bash
git branch --remote --list origin/*$1*
Then use it. (Make sure you set executable permissions.)
$: branchFilter # no argument
origin/HEAD -> origin/master
origin/bugfix/bar
origin/bugfix/foo
origin/dev
origin/feature/otherName
origin/feature/test
origin/hotfix/thisIsBroken
origin/master
origin/preprod
origin/production
origin/qa
origin/sit
origin/uat
origin/wip
$: branchFilter feature
origin/feature/otherName
origin/feature/test
$: branchFilter bugfix
origin/bugfix/bar
origin/bugfix/foo
$: branchFilter fix
origin/bugfix/bar
origin/bugfix/foo
origin/hotfix/thisIsBroken
If you really need the origin/ off the beginning, trim it with sed.
$: cat ~/bin/branchFilter
#!/bin/bash
git branch --remote --list origin/*$1* |
sed 's,origin/,,'
$: branchFilter fix
bugfix/bar
bugfix/foo
hotfix/thisIsBroken
If you just have to read from the input (I think it's a bad structure, but your program), it still works the same way.
$: cat ~/bin/branchFilter
#!/bin/bash
read str
git branch --remote --list "origin/*$str*" |
sed 's,origin/,,'

Count all the revisions for all files in a git project

Is there a git command that can output for every file in a project something like this or similar to it:
20 file1
43 file2 etc.
I'm interested to see how many times was each file modified by any author, not just for a specific one.
To get a sorted list of all files and the number of commits that modifies them:
git log --pretty='' --name-only | sort | uniq -c | sort -n
--pretty='': do not output commit information ('')
--name-only: print name of changed files only
sort | uniq -c: group file names and count number of occurrences (= number of commits modifying the file)
sort -n: numerical sort by number of modifications

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.

Using first 4 characters of file name to create unique list

I primarily use Linux Mint 17.1 and I like to use command line to get things done.
At the moment, I am working on organising a whole lot of family pictures and making them easy to view via a browser.
I have a directory with lots of images.
As I was filling the directory I made sure to keep the first four letters of the filename unique to a specific topic, eg, car_, hse_, chl_ etc
The rest of the filename keeps it unique.
There are some 120 different prefixes and I would like to create a list of the unique prefix.
I have tried 'ls i | uniq -d -w 4' and it works but it gives me the first filename of each prefix.
I just want the prefixes.
Fyi, I will use this list to generate an HTML page as a kind of catalogue.
Summary,
Convert car_001,car_002,car_003,dog_001,dog_002
to
car_,dog_
try this
$ ls -1 | cut -c1-3 | sort -u
uses the first 3 chars of the file names.
Try something like
ls -1 | cut -d'_' -f1 | uniq | sort
where cut splits the text by _ and takes the first field of each.

Resources