【问题标题】:Managing many git repositories管理许多 git 存储库
【发布时间】:2010-10-23 10:19:25
【问题描述】:

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

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

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

  1. 如何获取所有这些?
  2. 如何检查其中是否有未提交的更改?
  3. 如何检查其中是否有要合并的更改?

如果能够用一个命令来完成这些事情,那就太好了。

输出需要足够安静才能真正注意到要做的事情。

【问题讨论】:

  • answered hg mercurial 的相同问题。
  • 我使用代码编辑器(VS 代码)的多光标选择/多行编辑功能来创建批处理/shell 脚本并一次性执行。通过这个简单愚蠢的解决方案,我知道我在做什么以及我可以从执行这些命令中得到什么。无需猜测,无需学习,无需定制。另一个原因是,每次我想对驻留在公共父目录中的不同存储库集执行命令时。
  • 注意:使用 Git 2.30(2020 年第四季度),您现在拥有 new git for-each-repo command
  • github.com/earwig/git-repo-updater“gitup 是一个同时更新多个 git 存储库的工具。它足够聪明,可以处理多个远程、脏工作目录、分歧的本地分支、分离的 HEAD 等等。它最初是为了管理大量项目和处理零星的互联网访问而创建的。 gitup 应该可以在 macOS、Linux 和 Windows 上运行。你应该安装最新版本的 git 和 Python 2.7 或 Python 3。”

标签: git multiple-repositories


【解决方案1】:

我强烈推荐多个存储库工具mr。我曾经使用过一段时间其他人推荐的自定义 shell 脚本,但使用 mr 对我来说有以下好处:

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

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

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

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

【讨论】:

  • 很好,但不支持 git 标记(截至 2016-08)
  • @CADbloke 它没有在安装页面中提到 windows,但作为 Perl 脚本它可能/应该/可以在 windows 上工作。
  • @HugoZaragoza,你可以自己定义这个命令 [DEFAULT] tag = git tag "$@"
  • alias pa='find . -name .git -print -execdir git pull \;' 那么,pa 就够了
【解决方案2】:

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

所以,在尝试了 mr、repo 和 git-submodules 之后,我发现它们都缺少不同的方式,所以,我最终做了自己的变体:http://fabioz.github.io/mu-repo,这是一个成熟的工具——它有工作流这允许您:

  • 克隆多个存储库
  • 差异(和编辑)多个存储库中的当前更改
  • 预览传入的更改
  • 在多个存储库中并行运行命令
  • 创建存储库组
  • 在多个 repos 上运行与 git 无关的命令
  • 等(请参阅homepage 了解更多信息)。

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

【讨论】:

  • 您的回答表明 mu-repo 比 mr 更好。但是 mu-repo 不支持非 git repos。
  • 嗯,它的目的实际上是只支持 git repos(这是问题所问的)——虽然你也可以在多个 repos 中执行mu sh <some command> 来执行一些任意命令,但它的全部最终性是处理 git 而不是其他版本控制系统......如果你需要,那么是的,请使用不同的工具。
【解决方案3】:

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

【讨论】:

【解决方案4】:

您可以尝试使用repo 和自定义manifest.xml 文件来指定您的存储库的位置。如何做到这一点有some documentation

您也可以使用git-submodule(1)

【讨论】:

  • git-submodule 会很好,如果我想让存储库保持完全相同的状态,但事实并非如此。每个地方的存储库集都不相同。可能存在未提交的更改。可能有一些我不想合并的更改。
  • 我不知道 git-submodule。感谢您提及。
  • repo 的文档非常少,看起来它适用于我想要使用的不同类型的工作流程。
【解决方案5】:

我编写了一个名为“RepoZ”的工具,它会在您克隆 git 存储库或更改其中的任何内容(例如切换分支)时自动发现它们。

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

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

“我怎样才能获取所有这些?”

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

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

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

【讨论】:

  • 是的,太糟糕了,不值得。随时开放 PR。联系我。
【解决方案6】:

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

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

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

我怎样才能获取所有这些?

gita fetch

如何检查其中是否有未提交的更改?

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

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

如何检查其中是否有要合并的更改?

分支名称以 5 种方式着色

  • 白色:本地分支没有远程分支
  • 绿色:本地分支与远程分支相同
  • 红色:本地分支已与远程分支分道扬镳
  • 紫色:本地分支领先于远程分支(适合推送)
  • 黄色:本地分支在远程分支之后(适合合并)

要安装它,只需运行

pip3 install -U gita

【讨论】:

    【解决方案7】:

    gitslave 是一个工具,它可以通过在超级和子之间创建超级项目/子项目关系来在许多存储库上运行相同的命令。这(默认情况下)提供输出摘要,因此您可以专注于提供唯一输出的存储库(对 git status 有用,对 git ls-files 不太有用)。

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

    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
    

    【讨论】:

      【解决方案8】:

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

      这是代码:

      #!/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 "$@" \;
      }
      

      希望对你有帮助:)

      【讨论】:

      • 纤薄实用!
      • 太棒了!简单的单行输入.bash_aliases:alias rgit='function _rgit(){ find . -type d -name .git -printf "\n%p\n" -execdir git "$@" \;; }; _rgit'。来源它,然后例如致电rgit status
      【解决方案9】:

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

      #!/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 环境变量来覆盖它。

      此脚本基于this script

      【讨论】:

      • find . -name .git -print -execdir git pull \; 做你想做的事。
      • @DawnSong 你的精辟评论对我来说似乎是最好的答案! (虽然看起来这个答案中的脚本也回显了拉取调用?)
      【解决方案10】:

      您可以为此使用git-status-all gem:https://github.com/reednj/git-status-all

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

      还有一个 fetch 选项,它会在显示状态之前从所有存储库的源中获取:

      git status-all --fetch
      

      【讨论】:

      • 非常好的方法。与大多数投票率较高的工具相比,无需先注册存储库,而是简单地检查所有子目录。
      • find . -name .git -print -execdir git status \; 可以
      【解决方案11】:

      如果有人还在看这个帖子,请查看我的名为 gitme 的 shell 脚本

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

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

      脚本也贴在下面

      #!/bin/bash -e
      
      REPOS=( 
      /Users/you/gitrepo1
      /Users/you/gitrepo2
      /Users/you/gitrepo3
      /Users/you/gitrepo4
      )
      
      MOVE="Moving to next REPO... \n" 
      
      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_profile 中设置了一个别名,所以 alias gitme='sh /path/to/gitme.sh'

      【讨论】:

        【解决方案12】:

        为此,您可以使用every,它可以按照every <command>这种模式在多个目录中运行cli命令

        安装: npm i -g every-cli

        用法示例: every git branch

        - repo-1
          master
        - repo-2
          develop
        

        【讨论】:

          【解决方案13】:

          您应该查看 CPAN 上的 rgit,它会在目录树中的所有存储库上递归执行 git 命令。

          来自文档:

          此实用程序递归搜索 根目录(可能是 当前工作目录或 - 如果是 已设置 - 给定的目录 GIT_DIR 环境变量) 所有 git 存储库,对此列表进行排序 通过存储库路径,chdir 进入 他们每个人,并执行 指定 git 命令。

          【讨论】:

            【解决方案14】:

            我刚刚创建了一个工具,可以满足您的需求!

            1. 如何获取所有这些? gmaster fetch
            2. 如何检查其中是否有任何未提交的更改? gmaster status
            3. 如何检查其中是否有要合并的更改? gmaster status

            叫做gitmaster:https://github.com/francoiscabrol/gitmaster

            【讨论】:

              【解决方案15】:

              我将这个简单的 bash 函数写入我的 .bash_profile 以便能够在所有 git 存储库中运行 git、maven、gradle 或任何其他 bash 命令:

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

              可以这样使用

              all git st
              all git pull
              all ./gradlew clean test
              etc.
              

              【讨论】:

              • 也可以使用以下命令并行运行它们:all './gradlew clean test &'
              【解决方案16】:

              有一个方便的工具可以获取所有多个存储库。 git-pull-all 是一个命令行工具,可以在多个 git 存储库上异步执行。

              安装

              npm install -g git-pull-all
              

              用法

              假设你有这些文件和目录:

              ~/Projects/
                cool-examples/
                  .git/
                funny-movies/
                my-todos.txt
                super-express/
                  .git/
              

              当您在~/Projects 目录上运行git-pull-all 命令时,它应该会找到子 git 存储库(在上述情况下 cool-examplessuper-express)然后对他们每个人执行git pull

              $ cd ~/Projects
              $ git-pull-all
              funny-movies/
              Not a git repository
              cool-examples/
              Already up-to-date.
              super-express/
              Already up-to-date.
              Done!
              
              git-pull-all ~/Projects
              

              GitHub 链接:https://github.com/tatsuyaoiw/git-pull-all

              【讨论】:

                【解决方案17】:

                我找到了一个很好的解决方案,可以从所有具有 .git 文件夹的子目录中提取当前分支,即使每个 repo 都签出了不同的分支。 该命令是单行的,足够灵活,可以针对不同的 git 命令进行修改,并且可以别名。

                只需复制并粘贴以下内容:

                find . -type d -maxdepth 2 -name .git -exec sh -c 'cd $0 && cd .. && git pull origin $(git rev-parse --abbrev-ref HEAD)' {} \;
                

                分解:

                find . -type d -maxdepth 2 -name .git 
                

                在当前目录 (find .) 中查找名称为“.git” (-name .git) 的所有目录 (-type d),最多查找两个目录深度(2 而不是 1,因为我们是在 git repo 文件夹中寻找 git 文件夹)。

                -exec sh -c 
                

                运行以下shell命令(exec sh -c)

                'cd $0 && cd .. && git pull origin $(git rev-parse --abbrev-ref HEAD)'
                

                将目录更改为第一个参数(cd $0),然后将目录更改为上一级以离开 .git 文件夹(cd ..),然后执行 git pull origin 同时通过运行 git rev-parse... 指定分支当前分支的 HEAD 提交。

                {} \;
                

                “{}”是我们从初始 find 命令获得的结果相对路径。这 ;用于结束命令。

                在 zsh 上的 MacOS 10.14.6 上测试。按原样,仅当远程和本地分支命名相同时才有效,AFAIK。

                您可以修改它以获取状态。我希望您可以添加参数以进一步使其更加灵活,但我还没有尝试过。

                【讨论】:

                  【解决方案18】:

                  免责声明:我正在www.repoflow.com 开发此工具

                  如何获取所有这些?
                  如何检查其中是否有要合并的更改?

                  • 您可以获取所有涉及的存储库(或推送/拉取/提交它们),获取后 UI 将更新为新的存储库状态,如果存储库出现分歧,您可以查看冲突类型并开始合并它们.

                  如何检查其中是否有未提交的更改?

                  • 在 UI 上,您可以查看每个存储库的文件状态(您可以单独或批量添加/删除它们)。

                  我正在努力,但这也解决了 OP 问题并帮助管理多个存储库,您可以使用 UI 或底层 GraphQL API 创建自己的脚本,请考虑将其作为另一种选择。

                  【讨论】:

                    【解决方案19】:

                    我使用 Visual Studio 代码。我们的代码库中有大约 20 个库,它们都是独立的 Git 存储库,Visual Studio Code 中的源代码控制选项卡非常适合“一目了然”地查看本地存储库的落后或领先程度。还有一些设置可以定期获取以使该信息保持最新,以及刷新按钮。

                    它不像脚本那么方便,但在我的源代码控制方面,我喜欢做一个做出改变的人。需要编写非常好的脚本来小心不要覆盖更改等。使用 VS Code 方法,您可以快速获得大量信息,您可以自行采取行动。

                    这是它的截图:

                    【讨论】:

                      【解决方案20】:

                      我使用我的代码编辑器(VS 代码)的多光标选择/多行编辑功能来创建批处理/shell 脚本并一次性执行它。通过这个简单愚蠢的解决方案,我知道我在做什么以及我可以从执行这些命令中得到什么。无需猜测,无需学习,无需定制。另一个原因是,每次我想对位于公共父目录中的不同存储库集执行命令时。

                      【讨论】:

                        【解决方案21】:

                        请按照以下步骤从所有存储库中提取代码:

                        1. 使用扩展名为 .bat 创建一个新文件
                        2. 将该文件放在您拥有所有存储库文件夹的同一层次结构中
                        3. 编辑 .bat 文件并添加以下脚本
                        FOR /D %%G in (%cd%\*) Do cd %%G & call git branch & call git pull & cd ..
                        echo All code pulled successfully!!
                        pause
                        
                        1. 保存文件并双击开始拉取代码

                        【讨论】:

                          【解决方案22】:

                          https://github.com/wwjamieson3/envisionTools 有一个名为 gitstat 的 bash 脚本,它可以执行此操作以及更多其他功能。它与 GNU 和 mac 兼容。如果被要求,它可以从远程执行获取。它显示未跟踪、修改、添加、删除和暂存的文件。它通过在遥控器上显示未合并的提交和未推送的本地提交来与遥控器不同。它还可以以摘要或详细模式甚至 HTML 显示颜色编码的结果。它使用 locate 而不是 find,因为它的速度无限快,并且如果它变得太旧,甚至会提示更新您的 locate 数据库。

                          【讨论】:

                          • 感谢您发布您的答案!请务必仔细阅读FAQ on Self-Promotion。另请注意,每次链接到自己的网站/产品时,都要求发布免责声明。
                          • 很遗憾,github wwjamieson3/envisionTools 链接已损坏。
                          • @williamJamieson 是 envisionTools 是私有的 GitHub 存储库吗?
                          【解决方案23】:

                          看起来写一个脚本来做这件事很容易。本质上,它需要遍历存储库,然后使用 git ls-files、git diff 和 git log 等命令。

                          【讨论】:

                          • 我知道已经晚了,但你能发布脚本吗?
                          • 没有“脚本”。我正在使用我为自己的需要编写的脚本,但它不是通用的。
                          • "git diff" 如果你想获得一个可以通过单个补丁命令恢复和重新应用的单个差异文件,实际上是很棘手的。
                          • 从字面上看,任何答案都应该是公认的答案,但这个。
                          猜你喜欢
                          • 2012-12-31
                          • 2011-12-20
                          • 1970-01-01
                          • 2013-12-06
                          • 2020-02-01
                          • 2017-08-14
                          • 1970-01-01
                          • 1970-01-01
                          • 2011-06-13
                          相关资源
                          最近更新 更多