我正在研究的项目的一部分(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 (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过程也一样。线程显示它们处于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分钟后完成(它是一个巨大的存储库),并抛出异常:
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的解决方案,然后我将奖励赏金。
答案 0 :(得分:2)
我认为您的主要问题是模拟帐户的主目录不是您认为的,主要是因为模拟帐户的网络映射驱动器don't really work。
作为一种解决方法,您应该为模拟用户设置HOME环境变量以指向应包含您的ssh密钥(没有密码短语)的某个本地目录(例如在驱动器C:
上)。你应该通过手动运行git clone
来测试这一点(同时有假的HOME)并接受known_host密钥,这样就不会阻止后台git命令自动工作。
答案 1 :(得分:1)
家庭h:\有点宽泛,但除此之外,我会说你的下一步是创建一个具有正确权限的.ssh目录(h:.ssh),应该只为web用户阅读并且不允许任何其他用户访问。