0

I added an alias in my ~/.gitconfig:

[alias]
    h = "!git status -s | LC_ALL=C sort -k1 | my_function"

But when I call git h, I get:

> git h
git status -s|LC_ALL=C sort -k1| my_function: my_function: command not found

Now, I know that my function exists in my local shell. It's in my .bashrc and I can see it when I call compgen -A function:

> compgen -A function|grep my_function
my_function
> my_function
(expected output)

Why isn't git recognizing that I've already defined the function in my shell?

1 Answer 1

1

When git runs an alias, it actually runs it in a subprocess. If you start the alias with !, then it is translated into sh -C "$aliasWithoutBang" by the Git processor itself. This means it does not actually run in the same shell with the same variables or functions as the environment calling git.

What seems to be the better approach

h = bash -ic 'git status -s | LC_ALL=C sort -k1 | my_function'

This has two benefits.

  1. It uses an interactive shell (-i) and so loads the .bashrc.
  2. It specifically launches into bash.

Thanks to Glenn Jackman for the comments.


How I solved it

I expect there is a better way to do this, but I was able to resolve my problem by changing the alias to:

h = "!. ~/.bashrc && git status -s | LC_ALL=C sort -k1 | my_function"

Basically, I forced Git to re-load the environmental variables for this particular alias.

Sign up to request clarification or add additional context in comments.

6 Comments

You can also: (a) define the function in the file(s) that bash sources regardless of whether it's an interactive shell: this includes bashrc, so there's something funny going on here; (b) export the function to subshells; and/or (c) use a real script rather than a function.
@torek > "regardless of whether it's an interactive shell: this includes bashrc" ... not sure what shell you're thinking of, bash and sh don't read any startup files when invoked for scripting, only when invoked for login or interactively (without -c and on a tty).
Alternately, h = bash -ic 'git status -s | LC_ALL=C sort -k1 | my_function' -- the -i option specifies you want an interactive shell, and that will read your bashrc. It also specifically uses bash not sh
@torek The real lift here was figuring out why Git was ignoring my defined functions. Once I sorted that out, it was just a "OK, so I can just source bashrc first." And yes, I could have put it all into one script. That would have been much faster and conceptually better. But there was something that just wasn't working and I wanted to know why. So I opted for the slower, more painful approach of reading through Git's code instead of using an alternative. Because.. science!
BTW, if you want your defined functions to be available in child processes that are also running bash, that's what export -f -- exported functions -- are for. Though they do require that child shell to be bash; a /bin/sh won't see such functions.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.