管理多个Git仓库

118

在 Git 中设置项目非常容易,因此我甚至可以为小脚本设置单独的存储库。现在的问题是如何管理它们。

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

因此,我有一个包含许多存储库的目录。

  1. 如何获取所有存储库?
  2. 如何检查它们中是否有任何未提交的更改?
  3. 如何检查它们中是否有需要合并的更改?

最好能够用一个命令完成这些操作。

输出需要足够简洁,以便注意到需要处理的事项。


相同的问题已经为 hg mercurial 回答 - Serge Stroobandt
2
注意:自Git 2.30(2020年第四季度)起,您现在可以使用新的git for-each-repo命令。 - VonC
1
@sesm 你应该能够在 git for-each-repo 循环中运行 git rev-parse --git-dir 命令序列:这将显示每个存储库的根文件夹。 - VonC
1
@sesm 你可以运行 git for-each-repo --config=<config> -- xxx args:这将在 $PATH 中查找 git-xxx 可执行文件,其中你可以放置任意数量的逗号。 - VonC
@sesm 很棒,干得好! - VonC
显示剩余5条评论
26个回答

48

我强烈推荐使用多个存储库工具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)。 - Hugo Zaragoza
@CADbloke,安装页面上没有提到Windows,但作为Perl脚本,它可能/应该/可以在Windows上运行。 - scipilot
2
@HugoZaragoza,你可以随时自己定义这个命令[DEFAULT]tag = git tag "$@" - AlexS
4
“alias pa='find . -name .git -print -execdir git pull ;'” 的意思是创建一个名称为“pa”的命令别名,执行该别名时会在当前目录下查找所有名为“.git”的文件夹,并在每个文件夹中执行“git pull”命令以拉取最新的代码。之后只需输入“pa”即可执行该命令别名。 - DawnSong
这个工具是免费的吗?@Sandro Giessl,这个工具有什么缺点吗? - Sithija Piyuman Thewa Hettige

25

我必须说,我一开始采用了目前被接受的答案(一个遍历存储库的帮助脚本集合),但总的来说,这对我来说是一次不够满意的体验。

所以,在尝试了mr、repo和git子模块之后,我发现它们各自存在不同的缺点,因此最终我做了自己的变体:http://fabioz.github.io/mu-repo,这是一个成熟的工具 -- 它具有以下工作流程:

  • 克隆多个仓库
  • 在多个仓库中查看(并编辑)当前更改
  • 预览即将到来的更改
  • 并行在多个仓库中运行命令
  • 创建仓库组
  • 在多个仓库上运行非git相关命令
  • 等等(请参见主页获取更多信息)。

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


你的回答表明mu-repo比mr更好。但是mu-repo不支持非git仓库。 - Shaunak Sontakke
3
嗯,它的目的确实只是支持git仓库(这也是问题所问的) - 虽然你可以执行mu sh <some command>在多个仓库中执行一些任意命令,但它的最终目的是处理git而不是其他版本控制系统...如果你需要其他版本控制系统,那么请使用不同的工具。 - Fabio Zadrozny

17

gr(git-run)扩展了mr的功能(仅适用于git)。我发现使用其标签系统更容易组织多个git repo。但是,gr的代码维护不太好。如果您正在使用bash,请确保使用-t tag而不是#tag格式。


自那时起,开发工作似乎有所恢复:https://github.com/mixu/gr/graphs/contributors - Dave Forgac

13

我写了一个命令行工具叫做gita,用于管理多个代码库。它可以将已注册的代码库状态并排显示,例如:

enter image description here

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

现在使用这个工具来回答你的问题:

我如何获取所有这些?

gita fetch

我如何检查它们中是否有未提交的更改? gita ll命令显示分支名称旁边的3个可能符号,表示:
  • +: 暂存的更改
  • *: 未暂存的更改
  • _: 未跟踪的文件/文件夹
如何检查它们中是否有待合并的更改? 分支名称以5种方式着色:
  • 白色:本地分支没有远程分支
  • 绿色:本地分支与远程分支相同
  • 红色:本地分支与远程分支分歧
  • 紫色:本地分支领先于远程分支(适用于推送)
  • 黄色:本地分支落后于远程分支(适用于合并)
要安装它,只需运行
pip3 install -U gita

11
我写了一个名为 "RepoZ" 的工具,它可以自动发现 Git 仓库,只要你克隆它们或更改它们中的任何内容,比如切换分支。一旦找到,这些仓库就会被“跟踪”。这将简单地显示它们在本地仓库列表中,并包含类似于 posh-git 的密集状态信息。其中包括当前分支和其他信息,如文件编辑和传入或传出提交的数量。

RepoZ UI

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

RepoZ Navigation

"如何获取它们所有?"

Windows版本提供了一个上下文菜单来获取或拉取存储库。使用多选功能,您可以同时对多个存储库运行操作。

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

RepoZ Auto-Fetch

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

是的,太糟糕了,不值得。随时欢迎PR。给我发消息吧。 - Waescher
我是一个Windows用户,有很多代码库,这个工具非常不错。 - Zodman

10

你可以尝试使用 repo 工具来管理存储库,通过自定义的 manifest.xml 文件指定它们的位置。关于如何使用此工具,请参阅 相关文档

Android AOSP 项目 中,这是标准做法。

或者,您还可以使用 git-submodule(1)


2
如果我想保持存储库的确切状态,那么git-submodule是一个不错的选择,但事实并非如此。每个地方的存储库集不相同。可能存在未提交的更改。可能存在我不想合并的更改。 - iny
我之前不知道 git-submodule 这个功能,谢谢你提醒我。 - sykora
代码库的文档相当简略,看起来是为了不同的工作流程而设计的,与我想要使用的不太一样。 - iny
这是Android AOSP巨型项目的标准。不过,创建自定义的manifest.xml或与AOSP无关的任何内容似乎仍然不容易... - imbr

6
我已经创建了一个别名和一个函数,可以在指定目录下(递归地)运行所有可用存储库的任何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 "$@" \;
}

希望能帮到您:)

1
轻巧实用! - Kevin Chou
1
太棒了!将以下简单的一行代码放入.bash_aliases文件中:alias rgit='function _rgit(){ find . -type d -name .git -printf "\n%p\n" -execdir git "$@" \;; }; _rgit'。然后运行它,例如调用rgit status - ford04

5

gitslave是一个工具,可以通过创建超级项目/子项目之间的关系,在许多存储库上运行相同的命令。默认情况下,这提供了输出汇总,因此您可以集中精力处理提供唯一输出的存储库(对于git状态很有用,但对于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

5
我使用这个脚本来轻松地在所有仓库中执行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环境变量来覆盖此设置。

该脚本基于此脚本


1
find . -name .git -print -execdir git pull \; 的作用就是你想象的那样。 - DawnSong
1
@DawnSong,你简洁的评论对我来说似乎是最好的答案!(虽然这个答案中的脚本似乎也回显了拉取调用?) - noelicus

5
你可以使用git-status-all宝石来实现这一点: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

git status all


1
非常好的方法。与大多数得票较高的工具相比,无需先注册存储库,而是直接检查所有子目录。 - luator
find . -name .git -print -execdir git status \; 是可以的。 - DawnSong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接