In .gitconfig
I created an alias of this type:
[alias]
something = "!eval `ssh-agent -s` && ssh-add ~/.ssh/id_acub && git config --global user.email <email> && git config --global user.name <user.name>"
At this point, running git something
displays the information correctly, but it does not work as I expected.
If I type a line in the console:
eval `ssh-agent -s` && ssh-add ~/.ssh/id_acub && git config --global user.email <email> && git config --global user.name <user.name>
then everything works well.
What is wrong in the alias?
Let's start with a simpler example than ssh-agent -s
:
$ sh -c 'FOO=bar; echo FOO is now $FOO'
FOO is now bar
$ echo FOO is now $FOO
FOO is now
Why didn't this work? Why is my login shell's FOO
variable not set, when I set some other shell instance's FOO
variable?
Well, I hope the answer is obvious: my shell does not have FOO
set. I set some other shell's FOO
variable. I told that other shell to print it, and it was set. Then that other shell finished—exited—and gave control back to my login shell, and when I told my login shell to print my login shell's FOO
, it was not set.
What ssh-agent -s
does is print out some set of assignments. Let's try that:
$ sh -c 'echo FOO=bar'
FOO=bar
$ echo FOO is now $FOO
FOO is now
This did not work either, of course, because I simply printed some instructions. No one followed those instructions.
So let's try one more thing:
$ eval `sh -c 'echo FOO=bar'`
$ echo FOO is now $FOO
FOO is now bar
This time, I:
$FOO
and since the instructions I had my shell follow changed something in my shell, now my shell's FOO is set.
The design for ssh-agent
is the same: it does some work, then—in various modes including with -s
—prints out instructions for some shell to follow. You need the eval
to make that shell follow those instructions.
That's all good and does just what you want as long as the shell that's following these instructions is your shell. But when you make a Git alias, Git itself runs a new, different shell. That shell follows the instructions, and when it is done, your shell is unaffected.
What this means is that you cannot do what you want with a Git alias. You must use an alias or function that will affect your shell, not one that will start a new shell, affect it, and then have it terminate and have those effects evaporate.
Note that some changes, such as git config --global
, are stored in files, rather than in your shell. These changes don't evaporate when the shell vanishes. That's a key difference: file system state is stored outside individual processes. If everything ssh-agent
did were stored in file system state, it could be made to work, but some of the things ssh-agent
does are not stored there.