How to write portable Git library scripts?

I create custom Git commands by writing scripts in /usr/local/libexec/git and creating aliases to invoke them. For example:

git config --global alias.graph '!/usr/local/libexec/git/git-graph'

The tricky part is that I want my scripts to be "portable" in the sense that anyone who has installed Git should be able to install and run my scripts the same way I do, without encountering missing dependencies.

Important Edit: Following @Schwern's response, I realize I must add a bit more information. Replace "anyone who has installed Git" with "anyone who interacts with Git through the git-core scripts provided by the official Git sources". For example, invoking git rebase executes .../git-core/git-rebase.sh . (You can click that last word; it's a hyperlink, but it doesn't appear that way in all browsers.) I assume this is the situation for most Git users, as this is the default provided by the Git project itself.

From my years of experience writing portable shell scripts, I know it's futile to expect a shell script of even moderate complexity to run on every Unix-like OS that ever existed. However, I think it's reasonable to expect a common base of utilities to exist between Git workstations, at least enough to avoid constantly jumping through hoops and walking on eggshells when writing scripts to run on these workstations.

Here are my assumptions about the Git workstations:

  • All scripts in the git-core directory (eg /usr/libexec/git-core ) have not been altered since being placed there by the Git installation.
  • All scripts in git-core run as expected (ie same as on the Git maintainers' workstations, or anyone with a "normal" setup).
  • The installed version of Git meets some arbitrary minimum requirement that I have decided to support with my scripts. Edit: By "arbitrary", I really meant "convenient". @Schwern stated with precision what I was really trying to say here.
  • How can I determine the common base of utilities I can use to write portable scripts on these Git workstations?

    Edit: I am basically looking for a list of dependencies for the git-core scripts provided in the main Git distribution. This will give the common base I am looking for.


    In fact, all of Git's built in scripts (there are many, mostly sh and a few perl ) live in that git-core directory. Running git xxx attempts to execute program git-xxx , typically out of the git-core directory, after setting up various environment variables. For instance, git --git-dir=/path/to/some/dir exports a GIT_DIR=/path/to/some/dir setting.

    The precise location of the git-core directory itself is set when you build Git. You can view it by running:

    git --exec-path
    

    Note that while git foo will try to run $(git --exec-path)/git-foo , if there is no git-foo in there and you put git-foo in your own scripting directory (that is somewhere on your $PATH ), git foo will end up running that. The mechanism is straightforward: the git front end inserts the git-core path into the front of $PATH :

    $ cat << 'end' > $HOME/scripts/git-statusy
    ? #! /bin/sh
    ? echo statusy: $PATH is $PATH
    ? git status
    ? 'end'
    $ chmod +x $HOME/scripts/git-statusy
    $ git statusy
    statusy: $PATH is /usr/local/libexec/git-core:[...snipped]
    On branch master
    ... [snipped]
    

    Within the git-core directory, there is a file named git-sh-setup (qv). This contains some convenience functions and some workarounds for known issues on systems for which Git is built. A "core" Git script should therefore always begin with . git-sh-setup . git-sh-setup . (This works because $PATH has the git-core directory at the front.) Some "non-core" contrib scripts explicitly run . $(git --exec-path)/git-sh-setup . $(git --exec-path)/git-sh-setup instead though.

    Within your script, you can depend on any POSIX shell built-ins, except that you need to work around certain bugs (eg, FreeBSD /bin/sh mishandles return in some versions). Support for additional commands is basically on an "as found by testing" basis, as far as I know: if you look at the history of git-sh-setup.sh and other .sh files in the Git source, you will see various changes made over time to deal with such things.


    There's no such thing as a "Git workstation" anymore than there's an "SVN workstation" or even a "Ruby workstation". It's just some machine that has Git installed and is being used to work on or obtain some project that uses Git. If they're in a Windows environment, it will be Windows. If they're on an outdated Solaris machine, it will be a Solaris environment. Since Git now comes standard with OS X, every OS X machine is a "Git workstation".

    Because "Git workstation" includes Windows, and Windows doesn't come with any of the normal shell utilities, you can't use shell at all. At best you can rely on the minimal set that comes with Git Bash, but there are plenty of Windows/Git installations that don't use Git Bash. Instead, a lot of IDEs come with Git bundled in them.

    None of this changes the compatibility challenges of writing portable shell scripts. BSD vs Gnu vs some commercial monstrosity, and all with the problem of what about Windows, that will all still be there.

    None of this changes being polite about installing 3rd party extensions. They don't go into /usr , that's for system stuff and should remain unmodified. They go in something like /usr/local or even ~/bin . Git scripts will work if they are in the user's PATH .


    As to some of your assumptions about Git...

    All scripts in the git-core directory (eg /usr/libexec/git-core) have not been altered since being placed there by the Git installation.

    That's a fair assumption... if it exists. Here on OS X there is no /usr/libexec/git-core and I can't find any equivalent. I suspect they're all compiled into the binary. You can't assume Git is a pile of scripts or even has compatibility hard links like MacPorts does.

    All scripts in git-core run as expected (ie same as on the Git maintainers' workstations, or anyone with a "normal" setup).

    Again, that's a fine assumption if they exist which they don't have to.

    The installed version of Git meets some arbitrary minimum requirement that I have decided to support with my scripts.

    Rather than being arbitrary, pick the minimum version that supports the features your scripts need and that isn't too inconvenient for you. Always check it with git --version .


    With all that in mind, to be portable...

  • Use git directly, not via scripts.
  • Don't assume "git" is anything but a binary called git .
  • Have the installer ask for the location of the user's git binary.
  • Don't dump your own extensions into /usr/libexec, put them somewhere in the user's PATH.
  • Don't hard code any of the paths to where your extensions will be installed.
  • Don't write anything in shell or using Unix utilities.
  • Use a compiled language and provide binaries, or a commonly used scripting language like Perl or Python or Ruby and provide binary bundles.
  • 链接地址: http://www.djcxy.com/p/68196.html

    上一篇: 如何让Apache启动?

    下一篇: 如何编写可移植的Git库脚本?