Search code examples
windowssshgit-bash

Running SSH Agent when starting Git Bash on Windows


I am using git bash. I have to use

eval `ssh-agent.exe`
ssh-add /my/ssh/location/

every time when I start a new git bash.

Is there a way to set ssh agent permanently? Or does windows has a good way to manage the ssh keys?

I'm a new guy, please give me detailed tutorial, thanks!


Solution

  • 2013: In a git bash session, you can add a script to ~/.profile or ~/.bashrc (with ~ being usually set to %USERPROFILE%), in order for said session to launch automatically the ssh-agent.
    If the file doesn't exist, just create it.

    This is what GitHub describes in "Working with SSH key passphrases".

    The "Auto-launching ssh-agent on Git for Windows" section of that article has a robust script that checks if the agent is running or not.
    Below is just a snippet, see the GitHub article for the full solution.

    # This is just a snippet. See the article above.
    if ! agent_is_running; then
        agent_start
        ssh-add
    elif ! agent_has_keys; then
        ssh-add
    fi
    

    Other Resources:

    "Getting ssh-agent to work with git run from windows command shell" has a similar script, but I'd refer to the GitHub article above primarily, which is more robust and up to date.


    hardsetting adds in the comments (2018):

    If you want to enter the passphrase the first time you need it, and not when opening a shell, the cleanest way to me is:

    This way you don't even have to remember running ssh-add.


    And Tao adds in the comments (2022):

    It's worth noting why this script makes particular sense in Windows, vs (for example) the more standard linuxey script noted by @JigneshGohel in another answer:

    By not relying on the SSH_AGENT_PID at all, this script works across different msys & cygwin environments.
    An agent can be started in msys2, and still used in git bash, as the SSH_AUTH_SOCK path can be reached in either environment.
    The PID from one environment cannot be queried in the other, so a PID-based approach keeps resetting/creating new ssh-agent processes on each switch.


    szx mentions in the comments:

    There is a downside to this solution: Once you kill/exit the initial Git Bash bash.exe instance that started ssh-agent, the agent is not accessible by other shell instances until you open a new one. This is not good.

    Then you can modify the script to make sure ssh-agent persists across different Git Bash sessions. That would involve saving the agent's environment variables in a file that can be sourced by subsequent shells.

    Add the check for an existing ssh-agent process to your ~/.bashrc or ~/.profile, and connect to it, or start a new one if necessary:

    # Define a file to store the SSH agent environment variables
    SSH_ENV="$HOME/.ssh/environment"
    
    # Function to start ssh-agent and save its environment variables
    function start_agent {
        echo "Initializing new SSH agent..."
        # Start new ssh-agent, with the environment variables stored in SSH_ENV
        ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
        echo "succeeded"
        chmod 600 "${SSH_ENV}"
        . "${SSH_ENV}" > /dev/null
        ssh-add
    }
    
    # Source SSH settings, if applicable
    if [ -f "${SSH_ENV}" ]; then
        . "${SSH_ENV}" > /dev/null
        # Check if the agent is running
        ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
            start_agent;
        }
    else
        start_agent;
    fi
    

    The .ssh/environment is used to store the ssh-agent environment variables (SSH_AGENT_PID and SSH_AUTH_SOCK).

    • If the file exists, it sources (loads) the environment variables from it and checks if the ssh-agent process referenced by SSH_AGENT_PID is still running. If the process is not running, it starts a new ssh-agent and updates the .ssh/environment file with the new environment variables.
    • If the .ssh/environment file does not exist, it means no ssh-agent has been started yet, or the file was deleted. The script then initializes a new ssh-agent, saves the environment variables in .ssh/environment, and adds the SSH key.

    djvg also references in the comments the issue IDEA-253958

    What was confusing is that the in-build sftp client uses the ssh agent and Git does not. This line from you and the mentioned post helped:

    Once push works fine (and recongnized the agent) in cmd.exe, it should work in the IDE as well.

    The solution is to export the agent SSH_AUTH_SOCK into a legacy DOS variable. There's a tool for this, that works even without a restart of your computer or logoff/logon (isn't win 10 really evolved nowadays ;-):

    SETX SSH_AUTH_SOCK /tmp/ssh-XXXXXX/agent.0000
    

    Once you've done that, every new process picks up the environment variable and "bingo" git work from the IDE.
    Just start the IDE after the variable is exported.

    In my case as I have a rather complex agent setup (I use a yubikey for ssh auth) I start the agent in the recommended shell for git for windows (mingw), and then leak over the agent socket into the windows environment.

    #!/bin/bash
    
    # start the agent (just for display, my setup is way more complicated, but ends up in setting the SSH_AUTH_SOCK var just the like)
    eval $(ssh-agent.exe)
    # call the windows utility SETX to leak the SSH_AUTH_SOCK into the windows environment
    SETX SSH_AUTH_SOCK $SSH_AUTH_SOCK
    

    Of course, if you never use Git from the CLI, you might just start the agent from the windows CMD like it's explained in the referenced post.
    But I use Git quite a lot from the CLI, and this way I have the best of both worlds.