1

执行以下命令时,系统会提示我输入密码:

$ git pull
Enter passphrase for key (...)

当我尝试使用 Apache Commons Exec 以编程方式显示相同的信息时,程序卡住并且不打印任何内容:

CommandLine cmd = new CommandLine( "git" );
cmd.addArgument( "pull" );
DefaultExecutor executor = new DefaultExecutor();
executor.setStreamHandler( new PumpStreamHandler( System.out, System.err, System.in ) );
executor.execute( cmd );

为什么该示例没有打印任何内容就卡住了,并且在使用本机控制台时提示我提供 git 密码?

4

1 回答 1

2

发生这种情况是因为 SSH 密码短语应该是从pseudo terminalnot from读取的STDIN。您必须在父(您的程序)和子(git)进程之间创建一个伪 tty 通信流,并通过该流执行整个通信。看看Pseudo terminal to use with ssh in java了解一下。

还应该注意的是,它不git要求输入密码。git本身不执行任何身份验证,仅依赖于ssh(当然,仅适用于存储库,可通过 ssh 访问)。这是动作的顺序

  1. git检测到可以通过 ssh 访问给定存储库并调用 ssh 传输
  2. ssh 传输检测 ssh 身份验证代理是否在计算机上运行。
  3. 如果未检测到代理(您的情况),则传输切换到基于控制台的基本身份验证。ssh 需要一个“真正的控制台”,所以简单的标准输入/标准输出重定向是不够的。
  4. 或者如果 ssh 代理正在运行,则所有密钥验证都将传递给代理。
  5. 可能有不同的替代代理实现。有些只是要求用户输入密码来解锁 ssh 密钥,有些则在内存中保留一组预解锁的密钥等。根据代理性质,它可能会在控制台中显示密码提示或打开一个带有提示的新单独窗口。查看此页面,特别是关于 putty/pageant 的部分,以了解如何在 Windows 上设置 SSH 身份验证。

你可以看看pty4j,它使用 JNA 来实现终端和进程执行低级的东西。或者看看JGit,它是 git 的纯 java 重新实现,它根本不调用命令行 git。JGit 是Eclipse Git 插件Gerrit 代码审查系统的基础,因此它经过精心设计和完善。

于 2014-11-26T16:40:54.183 回答