Skip to content

Instantly share code, notes, and snippets.

@rmpel
Last active July 20, 2023 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rmpel/412df8ea7fd864602a24192cb0a02ae6 to your computer and use it in GitHub Desktop.
Save rmpel/412df8ea7fd864602a24192cb0a02ae6 to your computer and use it in GitHub Desktop.
Is this branched merged?

A script to check if your feature branches are merged.

Usage:

gitmerged.sh

Shows all open feature branches and their respective merge status to common root branches; master, main, staging, acc, develop

gitmerged.sh master staging

Shows only merged status to these two root branches

gitmerged.sh -master

Shows merged status to all but this root branch

<?php
$data = explode("\n", $argv[1]);
$data = array_map('trim', $data);
$options = $argv;
array_shift($options); // Remove script path
array_shift($options); // Remove DATA
$ignore_branches = [];
$use_only_branches = [];
foreach ($options as $option) {
if ('-' === substr($option, 0,1)) {
$ignore_branches[] = substr($option, 1);
}
else {
$use_only_branches[] = $option;
}
}
// Cannot use both USE ONLY and IGNORE at the same time.
if ($use_only_branches) {
$ignore_branches = [];
$add_branches = [];
}
// Find only feature branches.
function filter_branches($branch) {
list($origin, $main_branch, $feature_branch) = explode( "/", "$branch/" );
if ('origin' !== $origin) {
// we only work on "origin"
return false;
}
if (in_array($main_branch, ['HEAD', 'HEAD -> origin', 'main','master','staging','acc','develop'])) {
// we ignore well-known main branches
return false;
}
return true;
}
// strip parts.
function clean_branches($branch) {
return preg_replace('@^origin/@', '', trim($branch) );
}
$all_branches = []; // 1D
$main_branches = []; // 1D
$main_branches_sort = []; // 1D
$sort_values = [
'master' => 0,
'main' => 1,
'staging' => 2,
'acc' => 3,
'develop' => 4,
];
$merged_branches = []; // 2D
$trash = [];
$target = &$trash;
foreach ($data as $line) {
if (preg_match('/\-\-\- BEGIN (origin\/)?(.+)$/', $line, $m)) {
switch ($m[2]) {
case 'ALL':
$target = &$all_branches;
break;
default:
$b = $m[2];
$merged_branches[$b] = $merged_branches[$b] ?? [];
$target = &$merged_branches[$b];
$main_branches[] = $b;
$main_branches_sort[] = 'sort' . $sort_values[$b];
}
}
else if (preg_match('/\-\-\- END (origin\/)?(.+)$/', $line, $m)) {
$target = &$trash;
}
else {
$target[] = $line;
}
}
array_multisort($main_branches_sort, $main_branches);
if ($use_only_branches) {
$main_branches = array_intersect($main_branches, $use_only_branches);
}
if ($ignore_branches) {
$main_branches = array_diff($main_branches, $ignore_branches);
}
$all_branches = array_filter($all_branches, 'filter_branches');
$all_branches = array_values($all_branches);
$all_branches = array_map('clean_branches', $all_branches);
foreach( $merged_branches as &$merged_branche ) {
$merged_branche = array_filter($merged_branche, 'filter_branches');
$merged_branche = array_values($merged_branche);
$merged_branche = array_map('clean_branches', $merged_branche);
}
// build table
$table = [];
$table[] = array_merge( [ 'Branch' ], $main_branches );
foreach($all_branches as $branch) {
$row = [ $branch ];
foreach ($main_branches as $main_branch ) {
$row[] = in_array($branch, $merged_branches[ $main_branch ]) ? 'Yes' : 'No';
}
$table[] = $row;
}
print arrayToAsciiTable($table) ."\n";
function arrayToAsciiTable($array) {
$maxWidths = array();
$headerDone = 2;
foreach ($array as $row) {
foreach ($row as $key => $value) {
$maxWidths[$key] = max(strlen($value), isset($maxWidths[$key]) ? $maxWidths[$key] : 0);
}
}
$table = "";
foreach ($array as $row) {
if ($headerDone) {
$headerDone --;
$table .= "+";
foreach ($maxWidths as $width) {
$table .= str_repeat("-", $width + 2) . "+";
}
$table .= "\n";
}
$table .= "|";
foreach ($row as $key => $value) {
$table .= " " . str_pad($value, $maxWidths[$key], " ", STR_PAD_RIGHT) . " |";
}
$table .= "\n";
}
$table .= "+";
foreach ($maxWidths as $width) {
$table .= str_repeat("-", $width + 2) . "+";
}
return $table;
}
#!/usr/bin/env bash
CURDIR="$(pwd)";
TOOLDIR="$(realpath "$0")"
TOOLDIR="$(dirname "$TOOLDIR")"
[ ! -d .git ] && echo "This is not a git checkout, please go to the root of the project to check" && exit 1;
CURBR=$(git branch | grep \* | awk '{print $2}');
[ "master" != "$CURBR" ] && [ "develop" != "$CURBR" ] && [ "staging" != "$CURBR" ] && [ "main" != "$CURBR" ] && [ "acc" != "$CURBR" ] && echo "You are not on a main branch. Please go to master/main, staging/acc or develop" && exit;
MAINS=$( git branch -r --list origin/* | egrep '^[ \t]+origin/(master|develop|staging|main|acc)$' | egrep -o '(master|develop|staging|main|acc)' );
ONLY_MAINS=''
for option in $@; do
if [ "-" = "${option:0:1}" ]; then
MAINS=$(
for i in $MAINS; do
if [ $i != ${option:1} ]; then echo $i; fi
done
)
elif [ "" != "$(echo $MAINS | grep $option)" ]; then
ONLY_MAINS="$option $ONLY_MAINS"
fi
done
if [ "" != "$ONLY_MAINS" ]; then
MAINS=$ONLY_MAINS
fi
git diff --exit-code || echo "Not clean, sorry"
git diff --exit-code || exit 1
git fetch origin
DATA=$(
echo '--- BEGIN ALL'
git branch -r;
echo '--- END ALL'
for MAINBRANCH in $MAINS; do
git checkout $MAINBRANCH
git checkout .
git pull >/dev/null 2>&1
echo '--- BEGIN '$MAINBRANCH;
git branch -r --merged
echo '--- END '$MAINBRANCH;
done
)
# echo "$DATA" > debug.txt
git checkout $CURBR
git checkout .
php "$TOOLDIR"/gitmerged.php "$DATA" "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment