Search code examples
javagitapache-commonsapache-commons-exec

Why does "git pull" exec command get stuck and print nothing?


When executing the following command, I am prompted to type the password:

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

When I try to show the same information programatically using Apache Commons Exec, the program gets stuck and doesn't print anything:

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 );

Why does the example get stuck without printing anything, and while using the native console it prompts me to provide the git password?


Solution

  • This happens because the SSH passphrase is supposed to be read from a pseudo terminal not from STDIN. You have to create a pseudo tty communication stream between parent (your program) and child (git) processes and perform entire communication over that stream. Take a look at Pseudo terminal to use with ssh in java to get the idea.

    Also it should be noted that it's not git asks for passphrase. git itself doesn't perform any authentication, simply relying on ssh (of course, only for repositories, accessible via ssh). Here's the sequence of actions

    1. git detects that a given repository is accessible via ssh and invokes ssh transport
    2. ssh transport detects whether ssh authentication agent is running on the computer or not.
    3. If the agent is not detected (your case), then the transport switches to basic console-based authentication. ssh expects a "real console", so simple stdin/stdout redirection is not enough.
    4. or if the ssh agent is running then all key verification is passed to the agent.
    5. There could be different alternative agent implementations. Some simply ask user for a password to unlock a ssh key, other keep a set of pre-unlocked keys in memory etc. And depending on agent nature it may display password prompt in console or open a new separate window with a prompt. Check this page, particularly the part about putty/pageant to get the idea how SSH authentication can be set up on Windows.

    You may take a look at pty4j which uses JNA to implement terminal and process execution low level stuff. Or take a look at JGit which is a pure-java re-implementation of git, and it doesn't invoke command line git at all. JGit is a base for e.g Eclipse Git plugin or Gerrit Code review system so it's elaborated and polished.