3

我正在处理的项目的一部分(Windows、C#、MVC4 WebAPI)需要与 git 进行一些集成。现有的 C# git 库都不支持远程克隆,所以我最终移植了我们需要的JavaGit项目的部分(结帐、获取、状态),并自己编写了克隆。它实际上只是 git 命令行可执行文件的包装器。它调用的相关代码在这里:

public static void RunGitCommand(string repositoryPath, string gitArguments)
{
    // GitCommand is the full path to git.exe (currently using Github for Windows)
    if (null == GitCommand || String.IsNullOrWhiteSpace(GitCommand))
    {
        throw new FileNotFoundException("Unable to find git.exe on your system PATH.");
    }

    // gitArguments contains the command to run (e.g. "clone -- git@repo:projectName c:\repositories\repo_a8c0dd321f")
    var startInfo = new ProcessStartInfo(GitCommand, gitArguments)
    {
        WorkingDirectory = (null != repositoryPath && Directory.Exists(repositoryPath)) ? repositoryPath : String.Empty,
        CreateNoWindow = true,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardInput = true,
        RedirectStandardError = true
    };

    using (var p = new Process
    {
        EnableRaisingEvents = true,
        StartInfo = startInfo
    })
    {
        p.OutputDataReceived += (sender, args) => Log.Debug(args.Data);

        p.ErrorDataReceived += (sender, args) => Log.Debug(args.Data);

        p.Start();

        p.BeginOutputReadLine();
        p.BeginErrorReadLine();

        p.WaitForExit();
    }
}

代码将调用它:

// names changed to protect the innocent
string localRepo = @"c:\repositories\repo_a8c0dd321f";
string gitArgs = "clone -- git@repo:projectName c:\repositories\repo_a8c0dd321f";

GitConfiguration.RunGitCommand(localRepo, gitArgs);

在 MVC API 中,我们使用模拟来确保它以具有有效 git 登录名和密钥(无密码)的用户身份运行。上面的命令和我一样可以在命令行中完美运行,也可以在快速单元测试中运行(我知道这实际上是一个集成测试)。

但是,当它实际从 API 调用时,如上所示,它会挂起。查看任务管理器显示 git.exe 正在运行,命令行显示 git.exe 的完整路径,后跟上面的参数。它没有使用任何处理器时间,只有 2604K 的 RAM,但它声称正在运行。同样,有一个 ssh.exe 进程正在运行,也没有使用处理器,并且有 1212K 的 RAM,使用命令行:

ssh git@repo "git-upload-pack 'projectName'"

这两个进程都被列为在我的用户名下运行,因此看起来模拟工作正常。

查看 localRepo 目录,它创建了 .git 目录,然后挂起,在那里留下了大约 13K 的 git 文件,但没有我们的代码。认为这是由于我们的回购规模很大,我让它在一夜之间运行。到今天早上还没有动静。

提出了 LINQPad,运行:

Process.GetProcessById($gitPID).Dump()

对 SSH 进程也做了同样的事情。线程显示它们处于等待状态,并且 WaitReason 是执行(等待线程调度程序)。我最初认为它正在等待一个密码,因为我的钥匙有一个。我切换到没有密码的工作密钥,结果相同。

Git/SSH versions (from latest GitHub for Windows):
    git version
        git version 1.7.11.msysgit.1
    ssh -v
        OpenSSH_4.6p1, OpenSSL 0.9.8e 23 Feb 2007

我留下的唯一想法是它可能无法与正在运行的 ssh-agent 通信。不过,它正确地模拟了我,所以我不知道为什么它不能在 WebApi 框架中工作,但在“单元”测试和 Git Shell 中工作得很好。在查看了 Github for Windows 安装脚本后,我尝试确保设置了 HOME、PLINK_PROTOCOL、TERM、SSH_AUTH_SOCK 和 SSH_AGENT_PID 环境变量,以确保我没有遗漏任何内容。

我完全不知所措。这是日志文件的片段,之后有一些注释:

2012-11-20 13:42:59.5898 Info Initializing repo at path: c:\repositories\repo_a8c0dd321f 
2012-11-20 13:42:59.5898 Debug Working Directory: c:\repositories\repo_a8c0dd321f 
2012-11-20 13:42:59.6053 Debug C:\Users\christian.doggett\AppData\Local\GitHub\PortableGit_8810fd5c2c79c73adcc73fd0825f3b32fdb816e7\bin\git.exe status --branch 
2012-11-20 13:42:59.6209 Debug HOME=H:\ 
2012-11-20 13:42:59.6209 Debug PLINK_PROTOCOL=ssh 
2012-11-20 13:42:59.6365 Debug TERM=msys 
2012-11-20 13:42:59.6365 Debug SSH_AGENT_PID=58416 
2012-11-20 13:42:59.6365 Debug SSH_AUTH_SOCK=/tmp/ssh-IgTHj19056/agent.19056 
2012-11-20 13:42:59.6521 Info git status --branch
Exit code: 128

2012-11-20 13:42:59.6521 Error  
2012-11-20 13:42:59.6677 Info Cloning repo from origin: git@repo:projectName 
2012-11-20 13:43:01.8674 Debug Cloning into 'c:\repositories\repo_a8c0dd321f'... 
2012-11-20 13:43:03.2090 Debug Could not create directory 'h/.ssh'. 
2012-11-20 13:43:03.2870 Debug Warning: Permanently added 'repo,359.33.9.234' (RSA) to the list of known hosts. 
2012-11-20 13:44:41.4593 Debug fatal: The remote end hung up unexpectedly 

总是收到“无法创建目录 'h/.ssh'”和“警告:永久添加 * 到已知主机列表”。消息,甚至在命令行上。我的 H:.ssh\known_hosts 仍然是空的,但是我的密钥在那个目录中,并且 git 发现那些就好了。“远程端意外挂断”错误是在我杀死 git 和 ssh 进程时出现的。

我可能最终会切换到 LibGit2Sharp 来满足我的大部分需求,但这仍然不能解决我的克隆问题。我的密钥设置是否搞砸了,这又在 w3wp.exe 进程之外完美运行?它是否需要能够与 ssh-agent.exe 通信,而不能?有没有人通过 System.Diagnostics.Process 克隆了一个远程 git 存储库并活着讲述这个故事?

更新(2012 年 11 月 25 日下午 6:54):

mvp 指出模拟和映射网络驱动器不能很好地配合使用是正确的。在开始该过程之前,我添加了以下内容:

var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
Environment.SetEnvironmentVariable("HOME", userProfile);

我再次运行它,现在至少在任务管理器中看到了一个新的 git 进程,它占用了 0 个处理器时间,但正在使用越来越多的内存,我相信这是克隆进程的一部分。命令行是:

git index-pack --stdin --fix-thin "--keep=fetch-pack 6024 on MACHINENAME"

它终于在 10 分钟后完成(这是一个巨大的存储库),并抛出了异常:

fatal: git checkout: updating paths is incompatible with switching branches.
Did you intend to checkout 'origin/8b243b8d9a5140673fc552ef7da8f0dfe9039d50' which can not be resolved as commit?

不过,看起来克隆在更改到目录后工作了!另一个问题与克隆操作完成后立即调用 checkout 有关,但与挂起问题无关。

我只需要在生产服务器上验证我/mvp 的解决方案,然后我就会奖励赏金。

4

2 回答 2

2

我相信您的主要问题是模拟帐户的主目录不是您认为的那样,主要是因为模拟帐户的网络映射驱动器实际上不起作用

作为一种解决方法,您应该为模拟用户设置 HOME 环境变量以指向某个本地目录(比如在 drive 上C:),该目录应该包含您的 ssh 密钥(没有密码)。您应该通过git clone手动运行来测试它(同时使用假 HOME)并接受 known_host 键,因此它不会阻止后台 git 命令自动工作。

于 2012-11-25T09:02:16.090 回答
1

主页是 h:\ 有点宽泛,但除此之外,我想说你的下一步是创建一个具有正确权限的 .ssh 目录 (h:.ssh),应该只对 Web 用户读取,并且不能访问对于任何其他用户。

于 2012-11-20T21:14:58.150 回答