管理许多Git存储库

Managing many git repositories

在Git中设置项目很容易,因此即使对于小脚本,我也可以有单独的存储库。现在的问题是如何管理它们。

我在这些仓库的多个地方工作。当我对某个存储库进行了更改后,我希望能够在其他地方更新存储库。

所以我有一个目录,里面有很多存储库。

  • 我怎样才能把它们全部取走?
  • 如何检查其中是否有未提交的更改?
  • 如何检查其中是否有要合并的更改?
  • 如果能用一个命令来完成这些,那就太好了。

    输出需要足够安静,以实际注意到要做的事情。


    我强烈建议使用多存储库工具,Mr.我曾在一段时间内使用其他人推荐的自定义shell脚本,但使用mr对我有以下好处:

    • 它是通用的:可以使用各种版本控制系统的结合,而不仅仅是Git(例如Mercurial、SVN等)。
    • 这很快:Mr可以同时执行多个工作。我使用了许多Git/Mercurial存储库,并每天对它们进行多次同步。先生极大地加快了这一进程。
    • 管理存储库签出列表既简单又快捷。只需使用"mr register",而不是修改自定义脚本中的项目列表。

    关于静默输出的问题:可以使用命令行开关-q修改冗长级别。我更喜欢默认输出,它看起来可以很好地将输出统一在一个简短而清晰的摘要中。

    我对mr命令使用以下别名以确保mr始终获取存储在$home中的默认项目列表,并使用5个并行线程:

    1
    alias mr='mr -d ~/ -j 5 '


    我必须说,我从当前接受的答案开始(只是一堆在存储库中迭代的助手脚本),但总的来说,这对我来说是一种缺乏经验的体验。

    因此,在尝试了mr、repo和git子模块之后,我发现它们都有不同的不足之处,因此,我最终做了自己的变体:http://fabioz.github.io/mu-repo,这是目前成熟的工具——它有工作流,允许您:

    • 克隆多个回购
    • 差异(和编辑)多个回购中的当前更改
    • 预览传入更改
    • 并行运行多个repos中的命令
    • 创建回购组合
    • 在多个repos上运行与git无关的命令
    • 等(更多信息请参见主页)。

    注意,它支持任何运行python的操作系统;)


    gr(git run)扩展了mr的功能(仅适用于git)。我发现使用它的标签系统来组织多个git repos更容易。但是,gr的代码没有得到很好的维护。如果您使用bash,请确保将其与-t tag而不是#tag表单一起使用。


    您可以尝试将repo与自定义的manifest.xml文件一起使用,以指定存储库的位置。有一些关于如何做到这一点的文档。

    或者可以使用git-submodule(1


    gitslave是一种工具,它可以通过在super和subs之间创建超级项目/子项目关系,在多个存储库上运行相同的命令。这(默认情况下)提供了输出汇总,因此您可以将精力集中在提供唯一输出的存储库上(对于git状态很有用,对于git ls文件不太有用)。

    这通常用于需要将多个存储库组合在一起并同时将它们保存在同一分支或标记上的项目。对于我的(裸)存储库目录,我只有一个小的makefile,它允许我运行任意的git命令,如您所见,我主要用于fsck和gc:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    full: fsck-full gc-aggressive
            @:

    fsck-full:
            for f in */.; do (cd $$f; echo $$f; git fsck --full || echo $$f FAILED); done

    gc-aggressive:
            for f in */.; do (cd $$f; echo $$f; git gc --aggressive || echo $$f FAILED); done

    %:
            for f in */.; do (cd $$f; git $@ || echo $$f FAILED); done

    您可以使用git-status-allgem进行此操作:https://github.com/reednj/git-status-all

    1
    2
    3
    4
    5
    # install the gem    
    gem install git-status-all

    # use the status-all subcommand to scan the directory
    git status-all

    还有一个fetch选项,它将在显示状态之前从源站提取所有存储库:

    1
    git status-all --fetch

    git status all


    我使用这个脚本可以在我的所有存储库中轻松地执行git命令。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #!/bin/sh
    if [ !"$1" ="" ] ; then

       if ["$GITREPO" ="" -a -d"$HOME/cm/src" ] ; then
          GITREPO="$HOME/cm/src"
       fi

       if ["$GITREPO" !="" ] ; then

          echo"Git repositories found in $GITREPO"
          echo"-=-=-=-=-=-=-=-=-=-=-=-=-=-"

          DIRS="`/bin/ls -1 $GITREPO`"

          for dir in $DIRS ; do

             if [ -d $GITREPO/$dir/.git ] ; then
                echo"$dir -> git $1"
                cd $GITREPO/$dir ; git $@
                echo
             fi

          done
       else

          echo"Git repositories not found."

       fi
    fi

    默认情况下,脚本将在~/cm/src中查找git存储库,但您可以通过将gitrepo环境变量设置为您喜欢的值来覆盖它。

    此脚本基于此脚本。


    我编写了一个名为"repoz"的工具,它可以在克隆Git存储库或更改其中的任何内容(例如切换分支)时自动发现它们。

    一旦找到,存储库就会被"跟踪"。这将简单地在本地存储库列表中显示它们,其中包括受posh-git启发的密集状态信息。它包含当前分支和其他内容,如文件编辑和传入或传出提交的计数。

    RepoZ UI

    这有助于跟踪本地存储库以及要提交或推送的未完成工作。此外,还可以使用存储库列表作为导航,从一个存储库切换到另一个存储库。

    RepoZ Navigation

    "我怎样才能把它们全部取走?"

    Windows版本提供了一个上下文菜单来获取或提取存储库。通过多重选择,您可以同时在多个存储库上运行操作。

    但是,您可能会发现另一个功能非常有用:

    RepoZ Auto-Fetch

    通过自动获取,您可以告诉repoz在后台定期获取所有git存储库的远程设备。当然,这些获取不会与您的本地提交冲突。没有像git pull那样的本地合并尝试。


    我将这个简单的bash函数写入了我的.bash_概要文件中,以便仅在所有git存储库中运行git、maven、gradle或任何其他bash命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    # usefull function to work with multiple git repositories
    all() {
        failed=0
        printf '>>> START RUNNING:"%s">>>'"$*"
        for d in */; do
            pushd"$d"> /dev/null
            if [ -d".git" ]
            then
                printf '
    --------------------------------------------

    '
                pwd
                eval $@
                if [ $? -ne 0 ]
                then
                    failed=1
                    break;
                fi
            fi
            popd > /dev/null
        done
        if [ $failed -eq 0 ]
        then
            printf '
    --------------------------------------------
    '
            printf '<<< RAN"%s" WITH SUCCESS!!! <<<'"$*"
        else
            printf '
    <<< FAILED!!! <<<'
        fi
    }

    这个可以这样用

    1
    2
    3
    4
    all git st
    all git pull
    all ./gradlew clean test
    etc.


    我刚刚创建了一个工具来做你想做的!

  • 我怎样才能把它们全部取走?gmaster fetch
  • 如何检查其中是否有未提交的更改?gmaster status
  • 如何检查其中是否有要合并的更改?gmaster status
  • 它被称为gitmaster:https://github.com/francoiscabrol/gitmaster


    我已经创建了一个别名和一个函数来在目录中所有可用的存储库上运行任何git命令(递归)。你可以在这里找到它:https://github.com/jaguililla/dotfiles/git

    这是代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #!/bin/sh
    # To use it: source git_aliases

    # Example: rgita remote \;
    alias rgita='find . -type d -name .git -execdir git'

    # Example: rgit remote -vv
    rgit() {
      rgita"$@" \;
    }

    希望有帮助:)


    如果有人还在看这个线程,请签出我的shell脚本gitme

    您需要手动输入本地git repos,但我每天都使用此工具在多台计算机上协作多个git项目。

    你可以运行git clone https://github.com/robbenz/gitme.git

    脚本也发布在下面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    #!/bin/bash -e

    REPOS=(
    /Users/you/gitrepo1
    /Users/you/gitrepo2
    /Users/you/gitrepo3
    /Users/you/gitrepo4
    )

    MOVE="Moving to next REPO...
    "

    tput setaf 2;echo"What ya wanna do? You can say push, pull, commit, ftp push, or status"; tput sgr0

    read input

    if [ $input = "commit" ]
    then
        tput setaf 2;echo"Do you want a unique commit message? [y/n]";tput sgr0
        read ans
        if [ $ans ="y" ]
        then
            for i in"${REPOS[@]}"
            do
                cd"$i"
                tput setaf 6;pwd;tput sgr0
                git add . -A
                read -p"Commit description:" desc  
                git commit -m"$desc"
                tput setaf 2;echo  $MOVE;tput sgr0
                sleep 1
            done
        else
            for i in"${REPOS[@]}"
            do
                cd"$i"
                tput setaf 6;pwd;tput sgr0
                git add . -A
                git commit -m"autocommit backup point"
                tput setaf 2;echo  $MOVE;tput sgr0
                sleep 1
            done
        fi
    elif [ $input ="push" ] || [ $input ="pull" ] || [ $input ="ftp push" ] || [ $input ="status" ]
        then
            for i in"${REPOS[@]}"
    do
        cd"$i"
        tput setaf 6;pwd;tput sgr0
        git $input
        tput setaf 2;echo  $MOVE;tput sgr0
        sleep 1
        done
    else tput setaf 1;echo"You have zero friends";tput sgr0
    fi

    我在我的~/.bash_配置文件中设置了一个别名,所以alias gitme='sh /path/to/gitme.sh'


    我编写了一个名为gita的命令行工具来管理多个repos。例如,它并排显示已注册回购的状态。

    enter image description here

    它还可以从任何工作目录中委托git命令/别名。

    现在使用此工具回答您的问题:

    How can I fetch all of them?

    1
    gita fetch

    How can I check whether any of them have uncommitted changes?

    gita ls命令在分支名称旁边显示3个可能的符号,表示

    • +:阶段性变更
    • *:未老化变化
    • _:未跟踪的文件/文件夹

    How can I check whether any of them have changes to merge?

    分支名称有5种颜色

    • 白色:本地分支没有远程分支
    • 绿色:本地分支与远程分支相同
    • 红色:本地分支机构已偏离远程分支机构
    • 紫色:本地分支在远程分支之前(适合推送)
    • 黄色:本地分支位于远程分支之后(适合合并)

    要安装它,只需运行

    1
    pip3 install -U gita

    您应该在cpan上签出rgit,它递归地在目录树中的所有存储库上执行git命令。

    来自文档:

    This utility recursively searches in a
    root directory (which may be the
    current working directory or - if it
    has been set - the directory given by
    the GIT_DIR environment variable) for
    all git repositories, sort this list
    by the repository path, chdir into
    each of them, and executes the
    specified git command.


    https://github.com/wwjamieson3/envisiontools有一个名为gitstat的bash脚本,它可以实现这一点,还有更多功能。它与GNU和Mac兼容。如果需要,它可以从远程设备执行回迁。它显示未跟踪、修改、添加、删除和分段的文件。它通过在远程服务器上显示未合并的提交和未取消的本地提交与远程服务器不同。它还可以以摘要或详细模式显示颜色编码的结果,甚至可以显示HTML。它使用locate而不是find,因为它的速度是无限快的,如果数据库太旧,它甚至会提示更新locate数据库。


    看起来写一个脚本是很容易的。本质上,它需要迭代存储库,然后使用诸如git ls文件、git diff和git log之类的命令。