puggan icon

git_branch_compare

puggan | PRO | 03/21/17 10:10:46 PM UTC | 0 ⭐ | 635 👁️ | Never ⏰ | []
PHP |

5.08 KB

|

None

|

0 👍

/

0 👎

#!/usr/bin/env php
<?php
 
    $wd = getcwd();
 
    $git_dir = shell_exec('git rev-parse --show-toplevel');
 
    if(!$git_dir) {
        fprintf(STDERR, "Not inside a git path");
        exit(1);
    }
 
    $git_wd = substr($wd, strlen($git_dir));
 
    [$arguments, $flags] = parse_arguments(array_slice($argv, 1));
 
    $branches = [];
 
    if(count($arguments) == 1)
    {
        $branches['HEAD'] = hash_branch('HEAD', $flags);
    }
 
    foreach($arguments as $branch_name)
    {
        if(!isset($branches[$branch_name]))
        {
            $branches[$branch_name] = hash_branch($branch_name, $flags);
        }
    }
 
    $patch_index = [];
    foreach($branches as $branch_name => $branch_commits)
    {
        foreach($branch_commits as $commit)
        {
            if(empty($commit['patch_hash'])) continue;
            $patch_index[$commit['patch_hash']][$commit['commit_hash']] = $commit['branches'];
        }
    }
 
    $branch_compare_count = count($branches);
 
    foreach($patch_index as $patch_hash => $patch_commits)
    {
        $patch_branches = [];
        foreach($patch_commits as $commit_branches)
        {
            foreach($commit_branches as $branch_name)
            {
                $patch_branches[$branch_name] = $branch_name;
            }
        }
 
        $patch_branch_count = count($patch_branches);
        $first_commit = array_keys($patch_commits)[0];
        $first_branch = $patch_commits[$first_commit][0];
        $short_commit = substr($first_commit, 0, 7);
 
        if($patch_branch_count == $branch_compare_count)
        {
            if(count($patch_commits) > 1)
            {
                echo "{$short_commit} (ALL:cherry) {$branches[$first_branch][$first_commit]['title']}\n";
 
            }
            else
            {
                echo "{$short_commit} (ALL:same) {$branches[$first_branch][$first_commit]['title']}\n";
            }
        }
        else
        {
            echo "{$short_commit} (" . implode(', ', $patch_branches) . ") {$branches[$first_branch][$first_commit]['title']}\n";
        }
    }
 
    exit(0);
 
    function hash_branch($branch_name, $flags)
    {
        static $hashes = [];
 
        $cmd = 'git log --format="format:%H %s" ';
        if(!empty($flags['-c']))
        {
            $cmd .= ' -' . ((int) $flags['-c'][0]) . ' ';
        }
        if($branch_name)
        {
            $cmd .= escapeshellarg($branch_name);
        }
 
        $error = 0;
        $output = [];
        exec($cmd, $output, $error);
        if($error)
        {
            return FALSE;
        }
 
        $branch_hases = [];
 
        foreach($output as $row)
        {
            [$commit_hash, $commit_title] = explode(' ', $row, 2);
 
            if(!isset($hashes[$commit_hash]))
            {
                $hashes[$commit_hash] = load_commit($commit_hash, $commit_title, $flags);
            }
 
            $hashes[$commit_hash]['branches'][] = $branch_name;
            $branch_hases[$commit_hash] = &$hashes[$commit_hash];
        }
 
        return $branch_hases;
    }
 
    function load_commit($commit_hash, $commit_title, $flags)
    {
        $commit = ['commit_hash' => $commit_hash, 'title' => $commit_title, 'patch_hash' => NULL, 'branches' => []];
        $cmd = 'git show --format=format:%H ' . escapeshellarg($commit_hash);
        $error = 0;
        $output = [];
        exec($cmd, $output, $error);
        if($error)
        {
            return FALSE;
        }
 
        $compare_commit_hash = trim(array_shift($output));
 
        if($compare_commit_hash != $commit_hash)
        {
            return FALSE;
        }
 
        $hash_data = array();
        $include_file = TRUE;
        foreach($output as $row)
        {
            if(substr($row, 0, 5) == 'diff ')
            {
                if($flags AND isset($flags['-x']))
                {
                    $match = FALSE;
                    $row_parts = explode(' ', $row, 3);
                    foreach($flags['-x'] as $path)
                    {
                        $path = trim($path);
                        if(substr($path, 0, 1) == '/')
                        {
                            $path = substr($path, 1);
                        }
                        if(substr($path, -1) == '*')
                        {
                            $path = substr($path, 0, -1);
                        }
                        else if(substr($path, -1) != '/')
                        {
                            $path .= ' ';
                        }
                        if($row_parts[1] == '--git')
                        {
                            if(substr($row, 0, 13 + strlen($path)) == "diff --git a/{$path}")
                            {
                                $match = TRUE;
                                break;
                            }
                        }
                        else if($row_parts[1] == '--cc')
                        {
                            if(substr($row, 0, 10 + strlen($path)) == "diff --cc {$path}")
                            {
                                $match = TRUE;
                                break;
                            }
                        }
                    }
                    if($match)
                    {
                        $include_file = FALSE;
                        continue;
                    }
                }
 
                $include_file = TRUE;
                $hash_data[] = $row;
                continue;
            }
 
            if(!$include_file)
            {
                continue;
            }
 
            if(substr($row, 0, 6) == 'index ')
            {
                continue;
            }
 
            if(substr($row, 0, 3) == '@@ ')
            {
                $hash_data[] = '@@';
                continue;
            }
 
            $hash_data[] = $row;
        }
 
        if($hash_data)
        {
            $commit['patch_hash'] = sha1(implode(PHP_EOL, $hash_data));
        }
 
        return $commit;
    }
 
    function parse_arguments($raw_arguments)
    {
        $arguments = array();
        $flags = array();
 
        while($raw_arguments)
        {
            $current_arguemnt = array_shift($raw_arguments);
            if(substr($current_arguemnt, 0, 1) != '-')
            {
                $arguments[] = $current_arguemnt;
                continue;
            }
 
            if($current_arguemnt == '--')
            {
                while($current_arguemnt = array_shift($raw_arguments))
                {
                    $arguments[] = $current_arguemnt;
                }
                break;
            }
 
            $next_argument = array_shift($raw_arguments);
            $flags[$current_arguemnt][] = $next_argument;
        }
 
        return array($arguments, $flags);
    }

Comments