Tips and tricks

= git tips and tricks =
This page collect all git tips and tricks Koha developers have found 
 
= git =
== Hooks ==
A nice feature of git is hooks.
A hook is a small (or large) script that is executed before or after running some git command.
Hooks are located in the .git/hooks directory; To enable one simply add a file named after the hook point you wish to use to that directory and ensure it is executable.
=== pre-commit ===
A pre-commit hook will check for common coding issues before allowing you to complete a commit. You can find it in the koha-testing-docker project.
=== pre-applypatch ===
The pre-commit hook can also be useful as a pre-applypatch hook to catch issues with others bugs when applying via either `git am` or `git bz`.
=== pre-push ===
This pre-push hook will check for common coding mistakes before allowing the RM or RMaint to push to their community branch:
#!/usr/bin/perl
use Modern::Perl;
use List::MoreUtils qw( any );
use Term::ANSIColor qw(colored);
my $RELEASE = '19.06.x'; # The branch you are managing/maintaining
my $REMOTE = 'upstream'; # The name you gave to the remote for git.koha-community.org
my $SIGNATURE = q|Martin Renvoize <martin.renvoize@ptfs-europe.com>|; # Your signature for sign-off lines
my $remote = $ARGV[0];
my $minor = $RELEASE;
my $upstream = ( $RELEASE =~ m{^\d\d\.(05|11)\.x$} ) ? $RELEASE : 'main';
$minor =~ s/x//g;
if ( $remote eq $REMOTE ) {
 say "Running pre-push hook\n";
 # Check branch
 my $current_branch = `git branch | grep \\* | cut -d ' ' -f2`;
 chomp $current_branch;
 if ( $current_branch ne $RELEASE ) {
 say colored( "Current branch is not $RELEASE", 'red' );
 exit 1;
 }
 # Check commits exist
 my @commits = `git rev-list $REMOTE/$upstream..HEAD`;
 unless (@commits) {
 say colored( 'Hum... no commits to push?', 'green' );
 exit 1;
 }
 # Check commit messages are well formed
 my @errors;
 for my $commit (@commits) {
 say colored("Working on $commit", 'green');
 my $commit_message = `git log --format=%s -1 $commit`;
 if ( $commit_message !~ m|^Bug\s\d{4,5}: | ) {
 push @errors,
 colored( "Does not start with 'Bug XXXXX: ' - $commit", 'red' );
 }
 if ( $commit_message =~ m|DO NOT PUSH| ) {
 push @errors,
 colored( "Commit contains DO NOT PUSH - $commit", 'red');
 }
 if ( $commit_message =~ m|DBRev|i
 and not $commit_message =~ m|DBRev $minor| )
 {
 warn $commit_message;
 push @errors,
 colored( "DBRev is wrong, should start with 'DBRev $RELEASE'",
 'red' );
 }
 my $body = `git log --format=%b -1 $commit`;
 $body =~ s|\n\s*|\n|g;
 if ( $body !~ m|\n?Signed-off-by: $SIGNATURE| ) {
 push @errors, colored( "No Signed-off-by line - $commit", 'red' );
 }
 my $author_name = `git log --format=%an -1 $commit`;
 if ( $author_name eq 'John Doe' ) {
 push @errors, colored( "Bad author name - $commit", 'red' );
 }
 my $author_email = `git log --format=%ae -1 $commit`;
 if ( $author_email eq 'you@example.com' ) {
 push @errors, colored( "Bad author email - $commit", 'red' );
 }
 }
 # Check for remaining atomicupdate files
 my @atomicupdate_files =
`git show HEAD:installer/data/mysql/atomicupdate/|tr -s '\\n' | grep -v '^tree'|grep -v 'README'|grep -v skeleton`;
 chomp for @atomicupdate_files;
 for my $atomic (@atomicupdate_files) {
 push @errors, colored( "Atomicupdate file exists - $atomic", 'red' );
 }
 my @dbrev_files = `git show HEAD:installer/data/mysql/db_revs/|tr -s '\\n' | grep -v '^tree'`;
 chomp for @dbrev_files;
 for my $f ( @dbrev_files ) {
 my $mode = (stat("installer/data/mysql/db_revs/$f"))[2] & 07777;
 push @errors, "dbrev file is missing the +x flag - $f" if !($mode == 0775 || $mode == 0755);
 }
 # Check for missing CSS Compiles
 my $compiled = `yarn build && yarn build --view=opac`;
 my @css_changes = `git diff --name-only`;
 chomp for @css_changes;
 for my $css_change (@css_changes) {
 push @errors, colored( "CSS file changes exist - $css_change", 'red' );
 }
 # Report any errors
 if (@errors) {
 say colored($_, 'red') for @errors;
 exit 1;
 }
 say colored("Passed tests, pushing...", 'green');
}
exit 0;
This hook will prevent:
* to push a local branch that is not named "$RELEASE"
* to push commits that are not signed off by the RM/RMaint
* to push commits that do not start with "Bug XXXXX: "
* to push DBRev commits that do not correctly formatted ("DBRev $RELEASE")
* to push atomicupdate files
== Display the branch you're on ==
If you want to permanently display the branch you're on, edit your .bashrc file and add the following at the end: 
#prompt git
GIT_PS1_SHOWDIRTYSTATE=1
GIT_PS1_SHOWUNTRACKEDFILES=0
GIT_PS1_SHOWSTASHSTATE=1
GIT_PS1_SHOWUPSTREAM="verbose"
PS1='\D{%H:%M} \[\033[1;35m\]\w$(__git_ps1 " \[\033[1;34m\](%s)")\[\033[0m\]\$ '
 
your display will look like this: 
17:47 ~/koha.dev/koha-community (new/bug_7190 $%)$ 
 
displaying the directory you're on, the branch, and some informations about the status of your working directory 
== Git aliases to simplify command tasks ==
If you have Git-BZ installed, you can add the following aliases to your .gitconfig file to make applying a patch and reattaching it with your signoff a 1-command affair:
[alias]
 so = !sh -c 'prove t xt && git commit --amend -s && git bz attach -e $1 HEAD' -
 qa = !sh -c 'git fetch origin main && git checkout -b bug$1-qa origin/main&& git bz apply $1' -
 gr = log --graph --full-history --all --color --pretty=tformat:"%x1b[31m%h%x09%x1b[32m%x1b[0m%x20%d%s%x20%x1b[33m(%an)%x1b[0m"
 qa2 = "!f() { c=`expr $1 - 1`; git filter-repo --message-callback 'return message + b\"\\nSigned-off-by: Full Name <email>\"' --refs HEAD~$c^..; }; f"
You may need to install git filter-repo first.
=== git so #### ===
Runs automated tests, signs off on the patch and attaches it to the bug report, obsoleting the unsigned patch.
=== git qa #### ===
Fetches the latest main from git.koha-community.org, creates a new branch off that for the bug you're testing, then applies the patch from Bugzilla
=== git gr ===
Not BZ-specific, but this draws a character-mode graph showing the branch structure and displays it through your pager. 
=== git qa2 N ===
Not BZ-specific, this alias will add your signature to N patches.
git qa2 3 => deal with 3 patches
Category:Tips_&_Tricks
Category:Development
Category:Git
Category:Quality_Assurance_Testing