Git 递归推送所有子模块

Git 递归推送所有子模块,git,git-submodules,Git,Git Submodules,我编写了下面的脚本来推动工作区中的所有更改,包括子模块和超级项目。然而,这听起来有点奇怪,做我想做的事情是如此复杂。有没有更好的办法,让我错过 #!/bin/bash if [ "$#" -ne 1 ]; then echo "Illegal number of parameters" exit fi SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "${SCRIPT_DIR

我编写了下面的脚本来推动工作区中的所有更改,包括子模块和超级项目。然而,这听起来有点奇怪,做我想做的事情是如此复杂。有没有更好的办法,让我错过

#!/bin/bash

if [ "$#" -ne 1 ]; then
    echo "Illegal number of parameters"
    exit
fi

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

cd "${SCRIPT_DIR}/../submodule1" 
git status
git add -A
git commit -m "$1"
git push origin master

cd "${SCRIPT_DIR}/../submodule2" 
git status
git add -A
git commit -m "$1"
git push origin master

cd "${SCRIPT_DIR}/../submodule3" 
git status
git add -A
git commit -m "$1"
git push origin master

printf "\n\nUpdating Super Project\n\n" 
cd .. 
git status
git add -A
git commit -m "All Submodules Updated - $1"
git push origin master
git1.7.11([宣布]git1.7.11.rc1)提到:

“git push——递归子模块”学会了有选择地查看绑定到超级项目的子模块的历史记录并推送它们 出去

因此,您可以使用:

git push --recurse-submodules=on-demand

您可以使用
git submodule foreach
在每个子模块上运行任何所需的命令,例如

git submodule foreach git push origin master
请参阅:.

此c#console应用程序会提示您输入每个子模块的更改,并允许您轻松添加/提交/推送或运行自定义git命令:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

static class Program
{
    static readonly Process Proc = new Process();

static void Main(string[] args)
{
    Console.WindowHeight = (int) (Console.LargestWindowHeight * .8f);
    var dir = Path.GetFullPath(args.Length == 1 ? args[0] : Directory.GetCurrentDirectory());

    foreach (var module in GetModules(dir))
    {
        Console.WriteLine("Processing: " + module);
        PrintDiff(module, out var untracked, out var mods);

        if (!untracked && !mods)
            continue;

        while (true)
        {
            Console.WriteLine("Use \"c <msg>\" to commit and push" + (untracked ? ", \"a <msg>\" to also add untracked files" : "") + ", r to refresh.\nTo fix issues use git as normal, or cmd to enter prompt (exit to leave)" + ":");

            var cmd = Console.ReadLine();

            if (cmd.StartsWith("a "))
                Run("git", "add .", module);

            if (cmd.StartsWith("a ") || cmd.StartsWith("c "))
            {
                Run("git", "commit -a -m \"" + cmd.Substring(2) + "\"", module);
                Run("git", "push", module);
                break;
            }

            if (cmd.Trim() == "r")
            {
                PrintDiff(module, out untracked, out mods);
                if (!untracked && !mods)
                    break;
                continue;
            }

            try
            {
                var parts = cmd.Split(' ');
                Run(parts[0], cmd.Substring(parts[0].Length), module);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine();
            }
        }

        Console.WriteLine();
    }

    Console.WriteLine("Press any key to continue...");
    Console.ReadKey();
}

static void PrintDiff(string module, out bool untracked, out bool mods)
{
    var u = false;

    Run("git", "ls-files . --exclude-standard --others", module, s =>
    {
        u = true;
        Console.WriteLine("Untracked file: " + s);
    });

    var m = false;
    Run("git", "diff --staged", module, t =>
    {
        m = true;
        if (t.StartsWith("diff --git"))
            Console.WriteLine();
        Console.WriteLine(t);
    });

    Run("git", "diff", module, t =>
    {
        m = true;
        if (t.StartsWith("diff --git"))
            Console.WriteLine();
        Console.WriteLine(t);
    });

    if (m)
        Console.WriteLine();

    if (!u && !m)
    {
        Console.WriteLine("No changes");
        Console.WriteLine();
    }

    untracked = u;
    mods = m;
}

static List<string> GetModules(string dir)
{
    var l = new List<string>();
    var paths = new Queue<string>();
    var modules = new List<string>();
    paths.Enqueue("");

    while (paths.Count > 0)
    {
        var d = Path.Combine(dir, paths.Dequeue());
        if (!File.Exists(Path.Combine(d, ".gitmodules")))
            continue;

        Run("git", "config --file .gitmodules -l", d, t =>
        {
            var parts = t.Split('=');
            if (parts[0].EndsWith(".path"))
                l.Add(Path.Combine(d, parts[1]));
        });

        foreach (var s in l)
            paths.Enqueue(s);
        modules.AddRange(l);
        l.Clear();
    }

    modules.Reverse();
    return modules;
}

static void Run(string fileName, string arguments, string directory)
{
    Run(fileName, arguments, directory, Console.WriteLine);
    Console.WriteLine();
}

static void Run(string fileName, string arguments, string directory, Action<string> a)
{
    Proc.StartInfo = new ProcessStartInfo
    {
        FileName = fileName,
        Arguments = arguments,
        RedirectStandardOutput = true,
        WorkingDirectory = directory,
        UseShellExecute = false
    };
    Proc.Start();
    string t;
    while ((t = Proc.StandardOutput.ReadLine()) != null)
        a(t);
}
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.IO;
静态类程序
{
静态只读进程进程进程=新进程();
静态void Main(字符串[]参数)
{
Console.WindowHeight=(int)(Console.LargestWindowHeight*.8f);
var dir=Path.GetFullPath(args.Length==1?args[0]:Directory.GetCurrentDirectory());
foreach(GetModules(dir)中的var模块)
{
控制台写入线(“处理:+模块);
PrintDiff(模块、未跟踪的输出var、输出var mods);
如果(!untracked&&!mods)
继续;
while(true)
{
Console.WriteLine(“使用\“c\”提交并按“+(未跟踪?”,\“a\”同时添加未跟踪文件):“)+”,r刷新。\n要解决问题,请正常使用git,或使用cmd输入提示符(退出以离开)”+“:”;
var cmd=Console.ReadLine();
如果(cmd.StartsWith(“a”))
运行(“git”、“add.”模块);
if(命令启动带(“a”)| |命令启动带(“c”))
{
运行(“git”,“commit-a-m\”+cmd.Substring(2)+“m\”,模块);
运行(“git”、“push”、模块);
打破
}
如果(cmd.Trim()=“r”)
{
PrintDiff(模块、未跟踪输出、mods输出);
如果(!untracked&&!mods)
打破
继续;
}
尝试
{
变量部件=命令拆分(“”);
运行(部件[0],命令子字符串(部件[0].长度),模块);
}
捕获(例外e)
{
控制台写入线(e.Message);
Console.WriteLine();
}
}
Console.WriteLine();
}
Console.WriteLine(“按任意键继续…”);
Console.ReadKey();
}
静态无效打印差异(字符串模块、输出布尔未跟踪、输出布尔mods)
{
var u=假;
运行(“git”,“ls文件。--排除标准--其他”,模块,s=>
{
u=真;
Console.WriteLine(“未跟踪文件:+s”);
});
var m=假;
运行(“git”,“diff--staged”,模块,t=>
{
m=真;
if(t.StartsWith(“diff--git”))
Console.WriteLine();
控制台写入线(t);
});
运行(“git”,“diff”,模块,t=>
{
m=真;
if(t.StartsWith(“diff--git”))
Console.WriteLine();
控制台写入线(t);
});
如果(m)
Console.WriteLine();
如果(!u&&!m)
{
Console.WriteLine(“无变更”);
Console.WriteLine();
}
未追踪=u;
mods=m;
}
静态列表GetModules(字符串目录)
{
var l=新列表();
var路径=新队列();
var modules=新列表();
路径。排队(“”);
而(paths.Count>0)
{
var d=Path.Combine(dir,Path.Dequeue());
如果(!File.Exists(Path.Combine(d,.gitmodules)))
继续;
运行(“git”,“config--file.gitmodules-l”,d,t=>
{
var parts=t.Split('=');
if(部分[0].EndsWith(“.path”))
l、 添加(路径合并(d,部分[1]);
});
foreach(l中的变量s)
路径。排队;
模块。添加范围(l);
l、 清除();
}
模块。反向();
返回模块;
}
静态无效运行(字符串文件名、字符串参数、字符串目录)
{
运行(文件名、参数、目录、控制台.WriteLine);
Console.WriteLine();
}
静态无效运行(字符串文件名、字符串参数、字符串目录、操作a)
{
Proc.StartInfo=新流程StartInfo
{
FileName=FileName,
参数=参数,
重定向标准输出=真,
WorkingDirectory=目录,
UseShellExecute=false
};
Proc.Start();
字符串t;
而((t=Proc.standardpoutput.ReadLine())!=null)
a(t);
}
}

如果您有包含子模块的子模块,则命令git push--recurse submodules=on-demand不起作用。(
git
version:2.20.1)

~/.gitconfig
文件中添加以下别名:

[alias]
    push-all = "! find . -depth -name .git -exec dirname {} \\; 2> /dev/null | sort -n -r | xargs -I{} bash -c \"cd {}; git status | grep ahead > /dev/null && { echo '* Pushing: {}'; git push; }\""
然后在父git文件夹中发出
git-push-all

解释
  • :我们正在发出非git命令
  • find-depth-name.git-exec dirname{}\\;2> /dev/null
    :查找所有子模块(和git存储库,这不会造成损害)
  • | sort-n-r
    :按路径深度排序,最深的将排在第一位
  • |xargs-I{}bash-c\”
    :将目录传递给以下命令:
    • cd{};
      cd
      到目标目录
    • git status | grep ahead>/dev/null
      :测试是否需要推送此存储库
    • 和&{echo'*推送:{};git push;}\”
      :通知并推送

太好了!!谢谢!!