从MVC WebApi调用时挂起Git / SSH

我正在研究的项目的一部分(Windows,C#,MVC4 WebAPI)需要与git进行一些集成。 现有的C#git库都没有支持远程克隆,所以我最终移植了我们需要的JavaGit项目的部分(checkout,fetch,status),并自己编写了clone。 实际上它只是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 (eg "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登录和密钥(无密码)的用户身份运行。 上面的命令完全可以从我自己的命令行和快速unit testing中完成(我知道它实际上是一个集成测试)。

但是,当它实际上从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过程也是一样的。 线程显示它们处于Wait状态,WaitReason是Executive(等待线程调度程序)。 我最初认为它正在等待密码,因为我的密钥有一个密码。 我切换到没有密码的工作密钥,结果相同。

 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分钟后完成(它是一个巨大的存储库),并抛出exception:

 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,但与挂起问题无关。

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

我认为您的主要问题是模拟帐户的主目录不是您认为的,主要是因为模拟帐户的网络映射驱动器不能正常工作 。

作为一种解决方法,您应该为模拟用户设置HOME环境变量以指向一些本地目录(例如在驱动器C: :)上,该目录应该包含您的ssh密钥(没有密码短语)。 你应该通过手动运行git clone (同时有假的HOME)并接受known_host密钥来测试这一点,这样就不会阻止后台git命令自动运行。

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