利用PHP更新整个目录的全部.git仓库

这个脚本的目的就是一次性批量更新当前目录的全部.git项目,很多时候一到公司就需要同步N个仓库往往来不及,于是写个脚本提升工作效率。

<?php
declare(strict_types=1);//默认严格模式

$readDir = function($dir, $maxDepth) use (&$readDir) {
    if($maxDepth < 1) {
        return [];
    }
    $list = [];
    if($handle = opendir($dir)) {
        while(($name = readdir($handle)) !== false) {
            if($name == "." || $name == "..") {
                continue;
            }
            $path = $dir.DIRECTORY_SEPARATOR.$name;
            if(is_dir($path)) {
                $list[] = $path;
            }
        }
        closedir($handle);
    }
    $result = [];
    foreach($list as $item) {
        $baseName = basename($item);
        if($baseName === ".git") {
            $result[] = dirname($item);
        } else {
            $result = array_merge($result, $readDir($item, $maxDepth - 1));
        }

    }
    return $result;
};

$log = function(string $log) {
    echo "[".date("Y-m-d H:i:s")."]{$log}", PHP_EOL;
};

$dir = $argv[1] ?? null;
if(!empty($dir)) {
    if(!is_dir($dir)) {
        $log("目录不存在: {$dir}");
        exit(1);
    }
} else {
    $dir = __DIR__;
}

$dir = realpath($dir);
$log("读取目录: {$dir}");

$list = $readDir($dir, 4);

$log("读取GIT列表: ".count($list));

$updateGit = function($path) use (&$log) {
    $shell_exec_passthru = function($shell) use (&$log) {
        $log($shell);
        passthru($shell);
    };

    chdir($path);
    $branch_text = shell_exec("git branch");
    $branch_list = array_values(array_filter(array_map(function($a) {
        return trim($a);
    }, explode("\n", $branch_text))));

    if(empty($branch_list)) {
        $log("无任何分支需要更新");
        return;
    }
    $branch_list = (function($branch_list) {
        $list = [];
        $listTop = [];
        foreach($branch_list as $branch) {
            if($branch[0] == "*") {
                $listTop[] = trim(substr($branch, 1));
            } else {
                $list[] = $branch;
            }
        }
        return array_merge($listTop, $list);
    })($branch_list);

    $currentBranch = $branch_list[0];
    $log(sprintf("当前分支: %s", $currentBranch));
    $log(sprintf("全部分支列表: %s", PHP_EOL."----".implode(PHP_EOL."----", $branch_list)));

    $fetch_all = "git fetch --all -p";
    $log("更新全部分支: {$fetch_all}");
    $shell_exec_passthru($fetch_all);

    $behind_branch_list = (function() use (&$log) {
        $branch_info = shell_exec("git branch -v");
        $branch_info = array_map(function($v) {
            $v = trim($v);
            $v = trim($v, "*");
            $v = trim($v);
            $v = preg_replace("/[\s]{2,}/", " ", $v);
            $v = explode(" ", $v, 3);
            return $v;
        }, explode("\n", trim($branch_info)));

        $result = [];
        foreach($branch_info as $item) {
            if(empty($item)) {
                continue;
            }
            if(!isset($item[2])) {
                continue;
            }
            if(preg_match("/^\\[behind ([\\d]+)\\]/", $item[2], $match) > 0) {
                $log("{$item[0]}, behind: {$match[1]}");
                $result[] = $item[0];
            }
        }
        return $result;
    })();

    //依旧使用多个分支单独推送,由于每个分支可能会有更新
    $lastBranch = null;
    foreach($branch_list as $branch) {
        if(empty($branch)) {
            continue;
        }
        if(in_array($branch, $behind_branch_list)) {
            $shell_exec_passthru("git checkout {$branch}");
            $shell_exec_passthru("git pull origin");
            $lastBranch = $branch;
        }
    }

    if(!empty($lastBranch) && $lastBranch != $currentBranch) {
        $shell_exec_passthru("git checkout {$currentBranch}");
    }
    // $shell_exec_passthru("git checkout master");
};

$count = count($list);
foreach($list as $i => $path) {
    echo PHP_EOL, PHP_EOL;
    $log(sprintf("准备更新: %s, %d/%d", $path, $i + 1, $count));
    $updateGit($path);
}

4条评论在“利用PHP更新整个目录的全部.git仓库”

  1. 这个很有用,一堆GIt库代码一个个更新太麻烦~感谢分享。。。弱弱问句,这个在windows上怎么运行呢

写下你最简单的想法