Chapter 10. Customizing and Extending Git

Earlier chapters were designed to help you understand and master Git as a version control system, from examining history, through managing your contributions, to collaborating with other developers, ending with handling the composite projects in the last chapter: Chapter 9, Managing Subprojects—Building a Living Framework.

The following two chapters would help set up and configure Git, so that you can use it more effectively for yourself (this chapter) and help other developers use it (the next chapter).

This chapter will cover configuring and extending Git to fit one's needs. First, it will show how to set up a Git command line to make it easier to use. For some tasks though it is easier to use visual tools; the short introduction to graphical interfaces in this chapter should help you in choosing one. Next, there will be an explanation on how to change and configure Git behavior, from configuration files (with the selected configuration options described), to a per-file configuration with the gitattributes file.

Then this chapter will cover how to automate Git with hooks, describing for example how to make Git check whether the commit being created passes coding guidelines for a project. This part will focus on the client-side hook, and will only touch upon the server-side hooks— those are left for the, Chapter 11, Git Administration. The last part of the chapter will describe how to extend Git, from the Git command aliases, through integrating new user-visible commands, to helpers and drivers (new back-end abilities).

Many issues, such as gitattributes, remote and credential helpers, and the basics of the Git configuration should be known from the previous chapters. This chapter will gather this information in a single place and expand it a bit.

In this chapter, we will cover the following topics:

  • Setting up shell prompt and TAB completion for a command line
  • Types and examples of graphical user interfaces
  • Configuration files and basic configuration options
  • Installing and using various types of hooks
  • Simple and complex aliases
  • Extending Git with new commands and helpers

Git on the command line

There are a lot of different ways to use the Git version control system. There are many graphical user interfaces (GUIs) of varying use cases and capabilities, and there exists tools and plugins that allow integration with an integrated development environment (IDE) or a file manager.

However, the command line is the only place you can run all of the Git commands and which provides support for all their options. New features, which you might want to use, are developed for the command line first. Also, most of the GUIs implement only some subsets of the Git functionality. Mastering the command line always guarantees a deep understanding of tools, mechanisms, and their abilities. Just knowing how to use a GUI is probably not enough to get a founded knowledge.

Whether you use Git on a command line from choice, as a preferred environment, or you need it because it is the only way to access the required functionality, there are a few shell features that Git can tap into to make your experience a lot friendlier.

Git-aware command prompt

It's useful to customize your shell prompt to show information about the state of the Git repository we are in.

Note

Shell prompt is a short text message that is written to the terminal or the console output to notify the user of the interactive shell that some typed input is expected (usually a shell command).

This information can be as simple or as complex as you want. Git's prompt might be similar to the ordinary command-line prompt (to reduce dissonance), or visibly different (to be able to easily distinguish that we are inside the Git repository).

There is an example implementation for bash and zsh shells in the contrib/ area. If you install Git from the sources, just copy the contrib/completion/git-prompt.sh file to your home directory; if you have installed Git on Linux via a package manager, you will probably have it at /etc/bash_completion.d/git-prompt.sh. This file provides the __git_ps1 shell function to generate a Git-aware prompt in the Git repositories, but first you need to source this file in your.bashrc or .zshrc:

if [ -f /etc/bash_completion.d/git-prompt.sh ]; then
    source /etc/bash_completion.d/git-prompt.sh
fi

The shell prompt is configured using environment variables. To set up prompt, you must change directly or indirectly the PS1 (prompt string one, the default interaction prompt) environment variable. Thus, one solution to create a Git-aware command prompt is to include a call to the __git_ps1 shell function in the PS1 environment variable, by using command substitution:

export PS1='u@h:w$(__git_ps1 " (%s)")$ '

Note that, for zsh, you would also need to turn on the command substitution in the shell prompt with setopt PROMPT_SUBST command.

Alternatively, for a slightly faster prompt and with a possibility of color, you can use __git_ps1 to set PS1. This is done with the PROMPT_COMMAND environment variable in bash and with the precmd() function in zsh. You can find more information about this option in comments in the git-prompt.sh file; for bash, it could be:

PROMPT_COMMAND='__git_ps1 "u@h:w""\$ "" (%s)"'

With this configuration (either solution), the prompt will look as follows:

[email protected]:~/random/src (master)$

The bash and zsh shell prompts can be customized with the use of special characters, which get expanded by a shell. In the example used here, u means the current user (bob), h is the current hostname (host.company.org), w means the current working directory (~/random/src), while$ prints the $ part of the prompt (# if you are logged in as the root user). $(...) in the PS1 setup is used to call external commands and shell functions .__git_ps1 " (%s)" here calls the __git_ps1 shell function provided by git-prompt.sh with a formatting argument: the %s token is the place-holder for the presented Git status. Note that you need to either use single quotes while setting the PS1 variable from the command line, as in the example shown here, or escape shell substitution, so it is expanded while showing the prompt and not while defining the variable.

If you are using the __git_ps1 function, Git will also display information about the current ongoing multistep operation: merging, rebasing, bisecting, and so on. For example, during an interactive rebase (-i) on the branch master, the relevant part of the prompt would be master|REBASE-i. It is very useful to have this information right here in the command prompt, especially if you get interrupted in the middle of operation.

It is also possible to indicate in the command prompt the state of the working tree, the index, and so on. We can enable these features by exporting the selected subset of these environment variables (for some features you can additionally turn it off on per-repository basis with provided boolean-valued configuration variables):

Variable/Configuration

Values

Effect

GIT_PS1_SHOWDIRTYSTATE

bash.showDirtyState

Nonempty

This shows * for the unstaged changes and + for the staged changes.

GIT_PS1_SHOWSTASHSTATE

Nonempty

This shows $ if something is stashed.

GIT_PS1_SHOWUNTRACKEDFILES

bash.showUntrackedFiles

Nonempty

This shows % if there are untracked files in workdir.

GIT_PS1_SHOWUPSTREAM

bash.showUpstream

Space-separated list of values:

  • verbose
  • name
  • legacy
  • git
  • svn

This autoshows whether you are behind <, up to date "=", or ahead > of the upstream.name shows the upstream name and verbose shows the number of commits ahead/behind (with a sign). git compares HEAD to @{upstream} and svn to SVN upstream.

GIT_PS1_DESCRIBE_STYLE

One of values:

  • contains
  • branch
  • describe
  • default

This provides extra information when on detached HEAD. contains uses newer annotated tags, branch newer tag or branch, describe uses older annotated tags, default shows if there is exactly matching tag.

GIT_PS1_SHOWCOLORHINTS

(prompt command / precmd only)

Nonempty

Colored hint about the current dirty state and so on.

GIT_PS1_HIDE_IF_PWD_IGNORED

bash.hideIfPwdIgnored

Nonempty

Does not show a Git-aware prompt if the current directory is set to be ignored by Git.

If you are using the zsh shell, you can take a look at the zsh-git set of scripts, the zshkit configuration scripts, or the oh-my-zsh framework available for zsh, instead of using bash—first completion and prompt setup from the Git contrib/. Alternatively you can use the vcs_info subsystem built-in into zsh.

Well, there are alternate prompt solutions also for bash, for example git-radar.

Note

You can, of course, generate your own Git-aware prompt. For example, you might want to split the current directory into the repository path part and the project subdirectory path part with the help of the git rev-parse command.

Command-line completion for Git

Another shell feature that makes it easier to work with command-line Git is the programmable command-line completion. This feature can dramatically speed up typing Git commands. Command-line completion allows you to type the first few characters of a command, or a filename, and press the completion key (usually Tab) to fill the rest of the item. With the Git-aware completion, you can also fill in subcommands, command-line parameters, remotes, branches, and tags (ref names), each only where appropriate (for example, remote names are completed only if the command expects the remote name at a given position).

Git comes with built-in (but not always installed) support for the auto-completion of Git commands for the bash and zsh shells.

For bash, if the completion is not installed with Git (at /etc/bash_completion.d/git.sh in Linux by default), you need to get a copy of the contrib/completion/git-completion.bash file out of the Git source code. Copy it somewhere accessible, like your home directory, and source it from your .bashrc or .bash_profile:

. ~/git-completion.bash

Once the completion for Git is enabled, to test it you can type for example:

$ git check<TAB>

With Git completion enabled bash (or zsh) would autocomplete this to git checkout.

Similarly, in an ambiguous case, double Tab shows all the possible completions (though it is not true for all the shells):

$ git che<TAB><TAB>
checkout      cherry        cherry-pick

The completion feature also works with options; this is quite useful if you don't remember the exact option but only the prefix:

$ git config --<TAB><TAB>
--add              --get-regexp       --remove-section   --unset
--file=            --global           --rename-section   --unset-all
--get              --list             --replace-all
--get-all          --local            --system

Instead of the list of possible completions, some shells use (or can be configured to use) rotating completion, where with multiple possible completions, each Tab shows a different completion for the same prefix (cycling through them).

Note that the command-line completion (also called tab completion) generally works only in the interactive mode, and is based on the unambiguous prefix, not on the unambiguous abbreviation.

Autocorrection for Git commands

An unrelated, but similar to tab completion, built-in Git tool is autocorrection. By default, if you type something that looks like a mistyped command, Git helpfully tries to figure out what you meant. It still refuses to do it, even if there is only one candidate:

$ git chekout
git: 'chekout' is not a git command. See 'git --help'.

Did you mean this?
        checkout

However, with the help.autoCorrect configuration variable set to a positive number, Git will automatically correct and execute the mistyped commands after waiting for the given number of deciseconds (0.1 of second). You can use a negative value of this option for immediate execution, or zero to go back to default:

$ git chekout
WARNING: You called a Git command named 'chekout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...
Your branch is up-to-date with 'origin/master'.

If there is more than one command that can be deduced from the entered text, nothing will be executed. This mechanism works only for Git commands; you cannot autocorrect subcommands, parameters, and options (as opposed to tab completion).

Making the command line prettier

Git fully supports a colored terminal output, which greatly aids in visually parsing the command output. A number of options can help you set the coloring to your preference.

First, you can specify when to use colors and for output of which commands. There is a color.ui master switch to control output coloring to turn off all the Git's colored terminal outputs and set them to false. The default setting for this configuration variable is auto, which makes Git color the output when it's going straight to a terminal, but omit the color-control codes when the output is redirected to a file or a pipe.

You can also set color.ui to always, though you'd rarely want this: if you want color codes in your redirected output, simply pass a --color flag to the Git command; conversely, the --no-color option would turn off colored output.

If you want to be more specific about which commands are colored and which parts of the output are colored, Git provides appropriate coloring settings: color.branch, color.diff, color.interactive, color.status, and so on. Like with the master switch color.ui, each of these can be set to true, false, auto, and always.

In addition, each of these settings has subsettings that you can use to set specific colors for specific parts of the output. The color value of such configuration variables, for example, color.diff.meta (to configure the coloring of meta information in your diff output), consists of space-separated names of the foreground color, the background color (if set), and the text attribute.

You can set the color to any of the following values: normal, black, red, green, yellow, blue, magenta, cyan, or white. As for the attributes, you can choose from bold, dim, ul (underline), blink, and reverse (swap the foreground color with the background one).

The pretty formats for git log also include an option to set colors; see the git log documentation.

Alternative command line

To understand some of the rough edges of the Git user's interface, you need to remember that Git was developed to a large extent in the bottom-up fashion. Historically, Git began as a tool to write version control systems (you can see how early Git was used in the A Git core tutorial for developers documentation available at https://www.kernel.org/pub/software/scm/git/docs/gitcore-tutorial.html or https://git-scm.com/docs/gitcore-tutorial).

The first alternative "porcelain" for Git (alternative user interface) was Cogito. Nowadays, Cogito is no more; all of its features are long incorporated into Git (or replaced by better solutions). There were some attempts to write wrapper scripts (alternative UIs) designed to make it easy to learn and use, for example, Easy Git (eg).

There are also external Git porcelains that do not intend to replace the whole user interface, but either provide access to some extra feature, or wrap Git to provide some restricted feature set. Patch management interfaces, such as StGit, TopGit, or Guilt (formerly Git Queues (gq)), are created to make it easy to rewrite, manipulate, and clean up selected parts of the unpublished history; these were mentioned as an alternative to an interactive rebase in Chapter 8, Keeping History Clean. Then, there are single-file version control systems, such as Zit and SRC, which use Git as a backend.

Note

Besides alternative user interfaces, there are also different implementations of Git (defined as reading and writing Git repositories). They are at different stages of completeness. Besides core C implementation, there is JGit in Java, and also the libgit2 project—the modern basis of Git bindings for various programming languages.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset