简体   繁体   中英

Setting an environment variable in a git alias

If i wanted to set the value of foo to equal bar everytime I used git status how would I proceed to do this? My first thought would be to set an alias for status="status && foo=bar" but when I attempt that and echo $foo I do not get bar echoed however if I type it all out manually as git status && foo=baz and then echo $foo my output is baz. Why can't I declare the variable inside the alias? Also I've observed that if I were to switch the order up and for some reason do this alias git="foo=bar && git" and if I tried any git command and echoed foo it equals bar...

Git aliases are run by:

  • Git itself, if the alias does not start with ! : in this case you cannot set new environment variables; or
  • a POSIX-compatible shell, if the alias starts with ! .

POSIX-compatible shells allow setting environment variables in two ways:

VAR=value command

or:

VAR=value; export VAR; command1; command2; ...; commandN

This second variant can be written as:

export VAR=value; command1; ...; commandN

The explicitly exported variable is set for all the commands invoked this way—versus the VAR=value command , which sets it just for the one command—because this setting is done in the shell, and persists until the shell itself exits, and then the setting disappears with the shell that has exited. So if x is a Git alias:

git x

runs that alias, which can set an environment variable setting for the duration of any commands the alias itself runs. Then the shell that is running those commands exits, and all settings evaporate.

It's therefore literally impossible for a Git alias to set any environment variable in the command-line shell you use to run that alias. This is true for all commands, not just Git commands: no command can set environment variables in any "outer" shell.

There is one escape hatch, which is this: when you write a shell command yourself, you have control. For instance, you can write the rather silly shell command:

export VAR=$(echo value)

where the parenthesized $(echo value) is evaluated and then its output is substituted in. But this does mean that if some program prints some value you would like to save , you can write:

var=$(command)

which sets the local shell variable var to the output, or:

export VAR=$(command)

which sets the shell variable and exports it. (Note: the uppercase here is merely convention: local shell variables that are exported are conventionally written in all uppercase, while local shell variables that are not exported are conventionally written in all lowercase.)

There is a second escape hatch as well, but using it is risky: POSIX shells have an eval command which feeds text back to the shell interpreter. We can use this with programs that print export VAR1=value1; export VAR2=value2 export VAR1=value1; export VAR2=value2 as their output:

eval `ssh-agent -s`

Here, the ssh-agent program sets up the agent and then prints several appropriate export commands. However, should the ssh-agent program print rm -rf / , using eval ssh-agent -s will proceed to remove every file it can: this means you are placing a tremendous amount of trust on that ssh-agent command.

You can use a shell alias to make some easy-to-type-in command, such as gst , consist of both a variable-setting operation and a Git command:

alias gst='foo=bar && git status'

This is not a Git alias. This is a bash alias. Not all POSIX-compatible shells have shell aliases.

  • Regarding your shell's behavior :

If you write the following script :

# test.sh:
#!/bin/bash

foo=bar
echo "from script: $foo"

and you run it, you will see the following :

$ ./test.sh && echo "from cli: $foo"
from script: bar
from cli: 

running the script creates a fresh, new process with its own environment, foo=bar gets defined in that environment, and gets thrown away once the process exits.


To define set that variable in your current shell , you have to use other ways.

@torek mentioned :

  • calling eval ... with the output of your script
  • creating an alias

I'll also add :

  • invoke a function rather than a script :
$ mytest () {
   foo=bar
   echo "from function: $foo"
}

$ mytest && echo "from cli: $foo"
from function: bar
from cli: bar

  • Regarding git aliases :

git alias will always be executed as separate processes, you will have to use some other construct if you want to set an env variable that "outlives" the invocation.

You can for example define a function in your .bashrc :

mystatus () {
    git status && foo=bar
}

after that, you will be able to call mystatus from any shell you start.

If the command is that simple, it is really equivalent to a bash alias, the upside is that it will be easier to expand the content of that function if you need to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM