epubjs
Version:
Render ePub documents in the browser, across many devices
325 lines (202 loc) • 24.3 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Pro Git - professional version control</title>
<meta content="http://www.w3.org/1999/xhtml; charset=utf-8" http-equiv="Content-Type"/>
<link href="stylesheet.css" type="text/css" rel="stylesheet"/>
<style type="text/css">
@page { margin-bottom: 5.000000pt; margin-top: 5.000000pt; }</style>
</head>
<body class="calibre">
<h2 class="calibre4" id="calibre_pb_59">Git Configuration</h2>
<p class="calibre3">As you briefly saw in the Chapter 1, you can specify Git configuration settings with the <code class="calibre10">git config</code> command. One of the first things you did was set up your name and e-mail address:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
</code></pre>
<p class="calibre3">Now you'll learn a few of the more interesting options that you can set in this manner to customize your Git usage.</p>
<p class="calibre3">You saw some simple Git configuration details in the first chapter, but I'll go over them again quickly here. Git uses a series of configuration files to determine non-default behavior that you may want. The first place Git looks for these values is in an <code class="calibre10">/etc/gitconfig</code> file, which contains values for every user on the system and all of their repositories. If you pass the option <code class="calibre10">--system</code> to <code class="calibre10">git config</code>, it reads and writes from this file specifically. </p>
<p class="calibre3">The next place Git looks is the <code class="calibre10">~/.gitconfig</code> file, which is specific to each user. You can make Git read and write to this file by passing the <code class="calibre10">--global</code> option. </p>
<p class="calibre3">Finally, Git looks for configuration values in the config file in the Git directory (<code class="calibre10">.git/config</code>) of whatever repository you're currently using. These values are specific to that single repository. Each level overwrites values in the previous level, so values in <code class="calibre10">.git/config</code> trump those in <code class="calibre10">/etc/gitconfig</code>, for instance. You can also set these values by manually editing the file and inserting the correct syntax, but it's generally easier to run the <code class="calibre10">git config</code> command.</p>
<h3 class="calibre5">Basic Client Configuration</h3>
<p class="calibre3">The configuration options recognized by Git fall into two categories: client side and server side. The majority of the options are client side-configuring your personal working preferences. Although tons of options are available, I'll only cover the few that either are commonly used or can significantly affect your workflow. Many options are useful only in edge cases that I won't go over here. If you want to see a list of all the options your version of Git recognizes, you can run</p>
<pre class="calibre9"><code class="calibre10">$ git config --help
</code></pre>
<p class="calibre3">The manual page for <code class="calibre10">git config</code> lists all the available options in quite a bit of detail.</p>
<h4 class="calibre14">core.editor</h4>
<p class="calibre3">By default, Git uses whatever you've set as your default text editor or else falls back to the Vi editor to create and edit your commit and tag messages. To change that default to something else, you can use the <code class="calibre10">core.editor</code> setting:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global core.editor emacs
</code></pre>
<p class="calibre3">Now, no matter what is set as your default shell editor variable, Git will fire up Emacs to edit messages.</p>
<h4 class="calibre14">commit.template</h4>
<p class="calibre3">If you set this to the path of a file on your system, Git will use that file as the default message when you commit. For instance, suppose you create a template file at <code class="calibre10">$HOME/.gitmessage.txt</code> that looks like this:</p>
<pre class="calibre9"><code class="calibre10">subject line
what happened
[ticket: X]
</code></pre>
<p class="calibre3">To tell Git to use it as the default message that appears in your editor when you run <code class="calibre10">git commit</code>, set the <code class="calibre10">commit.template</code> configuration value:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global commit.template $HOME/.gitmessage.txt
$ git commit
</code></pre>
<p class="calibre3">Then, your editor will open to something like this for your placeholder commit message when you commit:</p>
<pre class="calibre9"><code class="calibre10">subject line
what happened
[ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C
</code></pre>
<p class="calibre3">If you have a commit-message policy in place, then putting a template for that policy on your system and configuring Git to use it by default can help increase the chance of that policy being followed regularly.</p>
<h4 class="calibre14">core.pager</h4>
<p class="calibre3">The core.pager setting determines what pager is used when Git pages output such as <code class="calibre10">log</code> and <code class="calibre10">diff</code>. You can set it to <code class="calibre10">more</code> or to your favorite pager (by default, it's <code class="calibre10">less</code>), or you can turn it off by setting it to a blank string:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global core.pager ''
</code></pre>
<p class="calibre3">If you run that, Git will page the entire output of all commands, no matter how long they are.</p>
<h4 class="calibre14">user.signingkey</h4>
<p class="calibre3">If you're making signed annotated tags (as discussed in Chapter 2), setting your GPG signing key as a configuration setting makes things easier. Set your key ID like so:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global user.signingkey <gpg-key-id>
</code></pre>
<p class="calibre3">Now, you can sign tags without having to specify your key every time with the <code class="calibre10">git tag</code> command:</p>
<pre class="calibre9"><code class="calibre10">$ git tag -s <tag-name>
</code></pre>
<h4 class="calibre14">core.excludesfile</h4>
<p class="calibre3">You can put patterns in your project's <code class="calibre10">.gitignore</code> file to have Git not see them as untracked files or try to stage them when you run <code class="calibre10">git add</code> on them, as discussed in Chapter 2. However, if you want another file outside of your project to hold those values or have extra values, you can tell Git where that file is with the <code class="calibre10">core.excludesfile</code> setting. Simply set it to the path of a file that has content similar to what a <code class="calibre10">.gitignore</code> file would have.</p>
<h4 class="calibre14">help.autocorrect</h4>
<p class="calibre3">This option is available only in Git 1.6.1 and later. If you mistype a command in Git 1.6, it shows you something like this:</p>
<pre class="calibre9"><code class="calibre10">$ git com
git: 'com' is not a git-command. See 'git --help'.
Did you mean this?
commit
</code></pre>
<p class="calibre3">If you set <code class="calibre10">help.autocorrect</code> to 1, Git will automatically run the command if it has only one match under this scenario.</p>
<h3 class="calibre5">Colors in Git</h3>
<p class="calibre3">Git can color its output to your terminal, which can help you visually parse the output quickly and easily. A number of options can help you set the coloring to your preference.</p>
<h4 class="calibre14">color.ui</h4>
<p class="calibre3">Git automatically colors most of its output if you ask it to. You can get very specific about what you want colored and how; but to turn on all the default terminal coloring, set <code class="calibre10">color.ui</code> to true:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global color.ui true
</code></pre>
<p class="calibre3">When that value is set, Git colors its output if the output goes to a terminal. Other possible settings are false, which never colors the output, and always, which sets colors all the time, even if you're redirecting Git commands to a file or piping them to another command. This setting was added in Git version 1.5.5; if you have an older version, you'll have to specify all the color settings individually.</p>
<p class="calibre3">You'll rarely want <code class="calibre10">color.ui = always</code>. In most scenarios, if you want color codes in your redirected output, you can instead pass a <code class="calibre10">--color</code> flag to the Git command to force it to use color codes. The <code class="calibre10">color.ui = true</code> setting is almost always what you'll want to use.</p>
<h4 class="calibre14"><code class="calibre10">color.*</code></h4>
<p class="calibre3">If you want to be more specific about which commands are colored and how, or you have an older version, Git provides verb-specific coloring settings. Each of these can be set to <code class="calibre10">true</code>, <code class="calibre10">false</code>, or <code class="calibre10">always</code>:</p>
<pre class="calibre9"><code class="calibre10">color.branch
color.diff
color.interactive
color.status
</code></pre>
<p class="calibre3">In addition, each of these has subsettings you can use to set specific colors for parts of the output, if you want to override each color. For example, to set the meta information in your diff output to blue foreground, black background, and bold text, you can run</p>
<pre class="calibre9"><code class="calibre10">$ git config --global color.diff.meta "blue black bold"
</code></pre>
<p class="calibre3">You can set the color to any of the following values: normal, black, red, green, yellow, blue, magenta, cyan, or white. If you want an attribute like bold in the previous example, you can choose from bold, dim, ul, blink, and reverse.</p>
<p class="calibre3">See the <code class="calibre10">git config</code> manpage for all the subsettings you can configure, if you want to do that.</p>
<h3 class="calibre5">External Merge and Diff Tools</h3>
<p class="calibre3">Although Git has an internal implementation of diff, which is what you've been using, you can set up an external tool instead. You can also set up a graphical merge conflict-resolution tool instead of having to resolve conflicts manually. I'll demonstrate setting up the Perforce Visual Merge Tool (P4Merge) to do your diffs and merge resolutions, because it's a nice graphical tool and it's free.</p>
<p class="calibre3">If you want to try this out, P4Merge works on all major platforms, so you should be able to do so. I'll use path names in the examples that work on Mac and Linux systems; for Windows, you'll have to change <code class="calibre10">/usr/local/bin</code> to an executable path in your environment.</p>
<p class="calibre3">You can download P4Merge here:</p>
<pre class="calibre9"><code class="calibre10">http://www.perforce.com/perforce/downloads/component.html
</code></pre>
<p class="calibre3">To begin, you'll set up external wrapper scripts to run your commands. I'll use the Mac path for the executable; in other systems, it will be where your <code class="calibre10">p4merge</code> binary is installed. Set up a merge wrapper script named <code class="calibre10">extMerge</code> that calls your binary with all the arguments provided:</p>
<pre class="calibre9"><code class="calibre10">$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*
</code></pre>
<p class="calibre3">The diff wrapper checks to make sure seven arguments are provided and passes two of them to your merge script. By default, Git passes the following arguments to the diff program:</p>
<pre class="calibre9"><code class="calibre10">path old-file old-hex old-mode new-file new-hex new-mode
</code></pre>
<p class="calibre3">Because you only want the <code class="calibre10">old-file</code> and <code class="calibre10">new-file</code> arguments, you use the wrapper script to pass the ones you need.</p>
<pre class="calibre9"><code class="calibre10">$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"
</code></pre>
<p class="calibre3">You also need to make sure these tools are executable:</p>
<pre class="calibre9"><code class="calibre10">$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff
</code></pre>
<p class="calibre3">Now you can set up your config file to use your custom merge resolution and diff tools. This takes a number of custom settings: <code class="calibre10">merge.tool</code> to tell Git what strategy to use, <code class="calibre10">mergetool.*.cmd</code> to specify how to run the command, <code class="calibre10">mergetool.trustExitCode</code> to tell Git if the exit code of that program indicates a successful merge resolution or not, and <code class="calibre10">diff.external</code> to tell Git what command to run for diffs. So, you can either run four config commands</p>
<pre class="calibre9"><code class="calibre10">$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
$ git config --global mergetool.trustExitCode false
$ git config --global diff.external extDiff
</code></pre>
<p class="calibre3">or you can edit your <code class="calibre10">~/.gitconfig</code> file to add these lines:</p>
<pre class="calibre9"><code class="calibre10">[merge]
tool = extMerge
[mergetool "extMerge"]
cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
trustExitCode = false
[diff]
external = extDiff
</code></pre>
<p class="calibre3">After all this is set, if you run diff commands such as this:</p>
<pre class="calibre9"><code class="calibre10">$ git diff 32d1776b1^ 32d1776b1
</code></pre>
<p class="calibre3">Instead of getting the diff output on the command line, Git fires up P4Merge, which looks something like Figure 7-1.</p>
<p class="calibre3"><img src="18333fig0701-tn.png" alt="Figure 7-1. P4Merge." title="Figure 7-1. P4Merge." class="calibre6"/></p>
<p class="calibre3">If you try to merge two branches and subsequently have merge conflicts, you can run the command <code class="calibre10">git mergetool</code>; it starts P4Merge to let you resolve the conflicts through that GUI tool.</p>
<p class="calibre3">The nice thing about this wrapper setup is that you can change your diff and merge tools easily. For example, to change your <code class="calibre10">extDiff</code> and <code class="calibre10">extMerge</code> tools to run the KDiff3 tool instead, all you have to do is edit your <code class="calibre10">extMerge</code> file:</p>
<pre class="calibre9"><code class="calibre10">$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*
</code></pre>
<p class="calibre3">Now, Git will use the KDiff3 tool for diff viewing and merge conflict resolution.</p>
<p class="calibre3">Git comes preset to use a number of other merge-resolution tools without your having to set up the cmd configuration. You can set your merge tool to kdiff3, opendiff, tkdiff, meld, xxdiff, emerge, vimdiff, or gvimdiff. If you're not interested in using KDiff3 for diff but rather want to use it just for merge resolution, and the kdiff3 command is in your path, then you can run</p>
<pre class="calibre9"><code class="calibre10">$ git config --global merge.tool kdiff3
</code></pre>
<p class="calibre3">If you run this instead of setting up the <code class="calibre10">extMerge</code> and <code class="calibre10">extDiff</code> files, Git will use KDiff3 for merge resolution and the normal Git diff tool for diffs.</p>
<h3 class="calibre5">Formatting and Whitespace</h3>
<p class="calibre3">Formatting and whitespace issues are some of the more frustrating and subtle problems that many developers encounter when collaborating, especially cross-platform. It's very easy for patches or other collaborated work to introduce subtle whitespace changes because editors silently introduce them or Windows programmers add carriage returns at the end of lines they touch in cross-platform projects. Git has a few configuration options to help with these issues.</p>
<h4 class="calibre14">core.autocrlf</h4>
<p class="calibre3">If you're programming on Windows or using another system but working with people who are programming on Windows, you'll probably run into line-ending issues at some point. This is because Windows uses both a carriage-return character and a linefeed character for newlines in its files, whereas Mac and Linux systems use only the linefeed character. This is a subtle but incredibly annoying fact of cross-platform work. </p>
<p class="calibre3">Git can handle this by auto-converting CRLF line endings into LF when you commit, and vice versa when it checks out code onto your filesystem. You can turn on this functionality with the <code class="calibre10">core.autocrlf</code> setting. If you're on a Windows machine, set it to <code class="calibre10">true</code> - this converts LF endings into CRLF when you check out code:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global core.autocrlf true
</code></pre>
<p class="calibre3">If you're on a Linux or Mac system that uses LF line endings, then you don't want Git to automatically convert them when you check out files; however, if a file with CRLF endings accidentally gets introduced, then you may want Git to fix it. You can tell Git to convert CRLF to LF on commit but not the other way around by setting <code class="calibre10">core.autocrlf</code> to input:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global core.autocrlf input
</code></pre>
<p class="calibre3">This setup should leave you with CRLF endings in Windows checkouts but LF endings on Mac and Linux systems and in the repository.</p>
<p class="calibre3">If you're a Windows programmer doing a Windows-only project, then you can turn off this functionality, recording the carriage returns in the repository by setting the config value to <code class="calibre10">false</code>:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global core.autocrlf false
</code></pre>
<h4 class="calibre14">core.whitespace</h4>
<p class="calibre3">Git comes preset to detect and fix some whitespace issues. It can look for four primary whitespace issues - two are enabled by default and can be turned off, and two aren't enabled by default but can be activated.</p>
<p class="calibre3">The two that are turned on by default are <code class="calibre10">trailing-space</code>, which looks for spaces at the end of a line, and <code class="calibre10">space-before-tab</code>, which looks for spaces before tabs at the beginning of a line.</p>
<p class="calibre3">The two that are disabled by default but can be turned on are <code class="calibre10">indent-with-non-tab</code>, which looks for lines that begin with eight or more spaces instead of tabs, and <code class="calibre10">cr-at-eol</code>, which tells Git that carriage returns at the end of lines are OK.</p>
<p class="calibre3">You can tell Git which of these you want enabled by setting <code class="calibre10">core.whitespace</code> to the values you want on or off, separated by commas. You can disable settings by either leaving them out of the setting string or prepending a <code class="calibre10">-</code> in front of the value. For example, if you want all but <code class="calibre10">cr-at-eol</code> to be set, you can do this:</p>
<pre class="calibre9"><code class="calibre10">$ git config --global core.whitespace \
trailing-space,space-before-tab,indent-with-non-tab
</code></pre>
<p class="calibre3">Git will detect these issues when you run a <code class="calibre10">git diff</code> command and try to color them so you can possibly fix them before you commit. It will also use these values to help you when you apply patches with <code class="calibre10">git apply</code>. When you're applying patches, you can ask Git to warn you if it's applying patches with the specified whitespace issues:</p>
<pre class="calibre9"><code class="calibre10">$ git apply --whitespace=warn <patch>
</code></pre>
<p class="calibre3">Or you can have Git try to automatically fix the issue before applying the patch:</p>
<pre class="calibre9"><code class="calibre10">$ git apply --whitespace=fix <patch>
</code></pre>
<p class="calibre3">These options apply to the git rebase option as well. If you've committed whitespace issues but haven't yet pushed upstream, you can run a <code class="calibre10">rebase</code> with the <code class="calibre10">--whitespace=fix</code> option to have Git automatically fix whitespace issues as it's rewriting the patches.</p>
<h3 class="calibre5">Server Configuration</h3>
<p class="calibre3">Not nearly as many configuration options are available for the server side of Git, but there are a few interesting ones you may want to take note of.</p>
<h4 class="calibre14">receive.fsckObjects</h4>
<p class="calibre3">By default, Git doesn't check for consistency all the objects it receives during a push. Although Git can check to make sure each object still matches its SHA-1 checksum and points to valid objects, it doesn't do that by default on every push. This is a relatively expensive operation and may add a lot of time to each push, depending on the size of the repository or the push. If you want Git to check object consistency on every push, you can force it to do so by setting <code class="calibre10">receive.fsckObjects</code> to true:</p>
<pre class="calibre9"><code class="calibre10">$ git config --system receive.fsckObjects true
</code></pre>
<p class="calibre3">Now, Git will check the integrity of your repository before each push is accepted to make sure faulty clients aren't introducing corrupt data.</p>
<h4 class="calibre14">receive.denyNonFastForwards</h4>
<p class="calibre3">If you rebase commits that you've already pushed and then try to push again, or otherwise try to push a commit to a remote branch that doesn't contain the commit that the remote branch currently points to, you'll be denied. This is generally good policy; but in the case of the rebase, you may determine that you know what you're doing and can force-update the remote branch with a <code class="calibre10">-f</code> flag to your push command.</p>
<p class="calibre3">To disable the ability to force-update remote branches to non-fast-forward references, set <code class="calibre10">receive.denyNonFastForwards</code>:</p>
<pre class="calibre9"><code class="calibre10">$ git config --system receive.denyNonFastForwards true
</code></pre>
<p class="calibre3">The other way you can do this is via server-side receive hooks, which I'll cover in a bit. That approach lets you do more complex things like deny non-fast-forwards to a certain subset of users.</p>
<h4 class="calibre14">receive.denyDeletes</h4>
<p class="calibre3">One of the workarounds to the <code class="calibre10">denyNonFastForwards</code> policy is for the user to delete the branch and then push it back up with the new reference. In newer versions of Git (beginning with version 1.6.1), you can set <code class="calibre10">receive.denyDeletes</code> to true:</p>
<pre class="calibre9"><code class="calibre10">$ git config --system receive.denyDeletes true
</code></pre>
<p class="calibre3">This denies branch and tag deletion over a push across the board - no user can do it. To remove remote branches, you must remove the ref files from the server manually. There are also more interesting ways to do this on a per-user basis via ACLs, as you'll learn at the end of this chapter.</p>
</body>
</html>