首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

Chapter 七. Customizing Git

2013-11-22 
Chapter 7. Customizing Git1.??Git uses a series ofconfiguration files to determine non-default beha

Chapter 7. Customizing Git

1.??Git uses a series ofconfiguration files to determine non-default behavior that you may want. Thefirst place Git looks for these values is in an /etc/gitconfig file which contains values for every user on the system andall of their repositories. If you pass the option --system to gitconfig?, it reads and writes from this filespecifically. The next place Git looks is the ?/.gitconfig?file, which is specific to each user. You can make Gitread and write to this file by passing the --global option. Finally, Git looksfor configuration values in the config file in the Git directory (.git/config) of whatever repository you're currently using. These valuesare specific to that single repository. Each level overwrites values in theprevious level.

?

2.? The configuration optionsrecognized by Git fall into two categories: client side and server side. If youwant to see a list of all the options your version of Git recognizes, you canrun:

$ git config --help

?

3.??By default, Git uses whateveryou've set as your shell default text editor or else falls back to the Vieditor to create and edit your commit and tag messages. To change that defaultto something else, you can use the core.editor setting:

$ git config --global core.editor emacs

?

4.??To tell Git to use a file asthe default message that appears in your editor when you run gitcommit, set the commit.template configuration value:

$ git config --global commit.template $HOME/.gitmessage.txt

?

5.??The core.pager setting determines what pager is used when Git pagesoutput such as log and diff. You can set it to more or to your favoritepager (by default, it's less), or you can turn it off (disablepaging) by setting it to a blank string:

$ git config --global core.pager ''

?

6.??If you're making signedannotated tags, setting your GPG signing key as aconfiguration setting makes things easier:

$ git config --global user.signingkey <gpg-key-id>

Now, you can sign tags withouthaving to specify your key every time with the git tag command:

$ git tag -s <tag-name>

?

7.??You can put patterns in yourproject's .gitignore?file to have Git not see themas untracked files if you want another file outside of your project to holdthose values or have extra values, you can tell Git where that file is with thecore.excludesfile?setting. Simply set it to the path of a file that hascontent similar to what a .gitignore?file would have.

?

8.??If you set help.autocorrect to 1?, Git will automatically run the uncompleted command if ithas only one match under this scenario. (Git 1.6.1 and above)

?

9.??To turn on all the defaultterminal coloring, set color.ui to true.When that value is set, Git colors its output if the output goes to a terminal.The other settings are false and always?,which sets colors all the time, even if you're redirecting Git commands to afile or piping them to another command. Always is seldom used, you caninstead pass a --color?flag to the Git command toforce it to use color codes.(Git 1.5.5 and above)

?

10.??Git provides verb-specificcoloring settings. Each of these can be set to true, false?, or always:

color.branch

color.diff

color.interactive

color.status

Each of these has subsettings you can use to set specificcolors for parts of the output. To set the meta information in your diffoutput to blue foreground, black background, and bold text, you can run:

$ git config --global color.diff.meta "blue black bold"

See the git config?manpage for all the subsettings you can configure.

?

11.??Visual Merge Tool (P4Merge) is agraphical merge conflict-resolution tool which you can download here:

http://www.perforce.com/perforce/downloads/component.html

?

12.??To use your custom mergeresolution and diff tools, You need to first prepare your merge and diffcommand wrapper:

$ cat /usr/local/bin/extMerge

#!/bin/sh/Applications/p4merge.app/Contents/MacOS/p4merge $*

$ cat /usr/local/bin/extDiff

#!/bin/sh

[ $# -eq 7 ] && /usr/local/bin/extMerge "$2""$5"

Git passes the following arguments to the diff program:

path old-file old-hex old-mode new-file new-hex new-mode

You only want the old-file and new-file?arguments.

Then you make these two wrapper executable and run:

$ 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

or you can edit your ?/.gitconfig file to add theselines:

[merge]

? tool = extMerge

[mergetool "extMerge"]

? cmd = extMerge"$BASE" "$LOCAL" "$REMOTE" "$MERGED"

? trustExitCode = false

[diff]

? external = extDiff

merge.tool to tell Git what strategyto use, mergetool.*.cmd to specify how to run the command, mergetool.trustExitCode?to tell Git if the exit code of that program indicates asuccessful merge resolution or not, and diff.external?to tell Git what command to run for diffs.

If you run diff commands, Git fires up P4Merge.If you try to merge two branches and subsequently have merge conflicts, you canrun the command git mergetool?; it starts P4Merge to let you resolve the conflicts throughthat GUI tool. The nice thing about this wrapper setup is that you can changeyour diff and merge tools easily.

?

13.??If you're programming onWindows, you'll probably run into line-ending issues at some point. BecauseWindows uses both a carriage-return character and a linefeed character fornewlines in its files, whereas Mac and Linux systems use only the linefeedcharacter. Git can handle this by auto-converting CRLF line endings into LFwhen you commit, and vice versa when it checks out code onto your file system.You can turn on this functionality with the core.autocrlf setting. If you're on a Windows machine, set it to true?—this converts LF endings into CRLF when you check outcode.

If you're on a Linux or Mac system, then you don't want Gitto automatically convert LF when you check out files. However,if a file with CRLF endings accidentally gets introduced, then you may wantGit to fix it. You can tell Git to convert CRLF to LF on commit but not theother way around by setting core.autocrlf to input.

?

14.??Git by default enables fix for trailing-space,which looks for spaces at the end of a line, and space-before-tab, whichlooks for spaces before tabs at the beginning of a line.

Git bydefault disables fix for indent-with-non-tab?,which looks for lines that begin with eight or more spaces instead of tabs, andcr-at-eol, which tells Git that carriage returns at the end oflines are OK. You can tell Git which of these you want enabled by setting core.whitespace?to the values you want on or off, separated by commas. Gitwill detect these issues when you run a git diff command and try to colorthem so you can possibly fix them before you commit. When you're applyingpatches, you can ask Git to warn you if it's applying patches with thespecified whitespace issues:

$ git apply --whitespace=warn <patch>

Or you can have Git try to automatically fix the issue beforeapplying the patch:

$ git apply --whitespace=fix <patch>

?

15.??If you want Git to check objectconsistency on every push, you can force it to do so by setting receive.fsckObjectsto true. Git will then check to makesure each object still matches its SHA-1 checksum and points to valid objects.(serverside config)

?

16.??To disable the ability toforce-update remote branches to non-fast-forward references:

$ git config --system receive.denyNonFastForwards true

(server side config)

?

17.??One of the workarounds to the denyNonFastForwardspolicy is for the user to delete the branch and then push it back up with thenew reference. You can set receive.denyDeletes to trueto avoid it. (Git 1.6.1 and above, server side config)

?

18.??Some of these settings can alsobe specified for a path, so that Git applies those settings only for asubdirectory or subset of files. These path-specific settings are called Git attributes and are set either in a .gitattribute?file in one of your directories or in the .git/info/attributes file if you don't want the attributes file committedwith your project. Using attributes, you cando things like specify separate merge strategies for individual files ordirectories in your project, tell Git how to diff non-text files, or have Gitfilter content before you check it into or out of Git.

?

19.??To tell Git to treat all pbxprojfiles as binary data, add the following line to your .gitattributes file:

*.pbxproj -crlf -diff

Now, Git won't try to convert or fix CRLFissues; nor will it try to compute or print a diff for changes in this filewhen you run git show or git diff on your project. In the 1.6series of Git, you can also use a macro that is provided that means -crlf-diff:

*.pbxproj binary

?

20.??Put the following line in your .gitattributesfile:

*.doc diff=word

This tells Git that any filethat matches this pattern (.doc) shoulduse the "word" filter when you try to view a diff that containschanges. You can setup the “word” filter by:

$ git config diff.word.textconv strings

This configures Git to use the strings?program to convert Word documents into readable textfiles. Now Git knows that if it tries to do a diff between two snapshots, andany of the files end in .doc?, itshould run those files through the "word" filter, which is definedas the strings program. strings?is available on most Mac and Linux systems, so it may be agood first try to do this with many binary formats.

?

21.??If you download and install theexiftool?program, you can use it to convert your images into textabout the metadata.

?

22.??You can inject text into a filewhen it's checked out and remove it again before it's added to a commit. Gitattributes offers you two ways to do this. You can inject the SHA-1 checksum ofa blob into an $Id$?field in the file automatically. It'simportant to notice that it isn't the SHA of the commit, but of the blobitself:

$ echo '*.txt ident' >> .gitattributes

$ echo '$Id$' > test.txt

$ git add test.txt

$ git commit

$ rm text.txt

$ git checkout -- text.txt

$ cat test.txt

$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $

?

23.??You can write your own filtersfor doing substitutions in files on commit/checkout. These are the "clean"and "smudge" filters. In the .gitattributes file, youcan set a filter for particular paths and then set up scripts that will processfiles just before they're committed and just before they're checked out:


Chapter 七. Customizing Git
?
Chapter 七. Customizing Git

You can set the filter attribute in your .gitattributes:

*.c???? filter=indent

Then, define the “intent” filter: (tell Git what itdoes on smudge and clean):

$ git config --global filter.indent.clean indent

$ git config --global filter.indent.smudge cat

?

24.??Another example of filter is toreplace $Date$ with the commit date when git checkout and roll back thechanges when git add. You can set your smudge script in ruby:

#! /usr/bin/env ruby

data = STDIN.read

last_date = 'git log --pretty=format:"%ad" ?1'

puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')

And your clean script can be a simple perl script:

$ git config filter.dater.smudge expand_date

$ git config filter.dater.clean 'perl -pe"s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'

Then you can test it:

$ echo '# $Date$' > date_test.txt

$ echo 'date*.txt filter=dater' >> .gitattributes

$ git add date_test.txt .gitattributes

$ git commit -m "Testing date expansion in Git"

$ rm date_test.txt

$ git checkout date_test.txt

$ cat date_test.txt

# $Date: Tue Apr 21 07:26:52 2009 ?0700$

?

25.??If you have some test files ina test/?subdirectory, and it doesn't make sense to includethem in the tarball export of your project. You can add the following line toyour Git attributes file:

test/ export-ignore

Now, when you run git archive to create a tarball ofyour project, that directory won't be included in the archive.

?

26.? Git lets you put the string $Format:$ in any file with any of the --pretty=format?formatting shortcodes. For instance, if you want toinclude a file named LAST_COMMIT?in your project, and the last commit date wasautomatically injected into it when git archive ran, you can:

$ echo 'Last commit date: $Format:%cd$' > LAST_COMMIT

$ echo "LAST_COMMIT export-subst" >> .gitattributes

$ git add LAST_COMMIT .gitattributes

$ git commit -am 'adding LAST_COMMIT file for archives'

?

27.??If you have a database settingsfile called database.xml that is different in two branches, and you want tomerge in your other branch without messing up the database file. You can set upan attribute like this:

database.xml merge=ours

If you merge in the other branch, instead of having mergeconflicts with the database.xml file, you see something like this:

$ git merge topic

Auto-merging database.xml

Merge made by recursive.

?

28.??Git has a way to fire offcustom scripts when certain important actions occur. There are two groups ofthese hooks: client side and server side. The client-side hooks are for client operations such as committing andmerging. The server-side hooks are for Git serveroperations such as receiving pushed commits.

?

29.? The hooks are all stored in thehookssubdirectory of the Git directory. In most projects, that's .git/hooks. Git populates this directory with a bunch of examplescripts. For post-1.6 versions of Git, these example hook files end with .sample; you'll need to rename them. For pre-1.6 versions ofGit, the example files are named properly but are not executable. To enable ahook script, put a file in the hooks?subdirectory of your Git directory that is named appropriately and isexecutable.

?

30.??The pre-commit hook is runfirst, before you even type in a commit message. It's used to inspect thesnapshot that's about to be committed. Exiting non-zero from this hook abortsthe commit, although you can bypass it with gitcommit --no-verify?. You can do things likecheck for code style (run lint?),check for trailing whitespace (the default hook does exactly that), or checkfor appropriate documentation on new methods.

?

31.??The prepare-commit-msg?hook is run before the commit message editor is fired upbut after the default message is created. It lets you edit the default messagebefore the commit author sees it. This hook takes a few options: the path tothe file that holds the commit message so far, the type of commit, and thecommit SHA-1 if this is an amended commit. It's good for commits where thedefault message is auto-generated, such as templated commit messages, mergecommits, squashed commits, and amended commits. You may use it in conjunctionwith a commit template to programmatically insert information.

?

32.??The commit-msg?hook takes one parameter, which again is the path toa temporary file that contains the current commit message. If this script exitsnon-zero, Git aborts the commit process, so you can use it to validate yourproject state or commit message(whether it’s conformant to a required pattern)before allowing a commit to go through.

?

33.??After the entire commit processis completed, the post-commit hook runs. It doesn't take any parameters, but youcan easily get the last commit by running git log ?1 HEAD?. Generally, this script is used for notification orsomething similar.

?

34.??The client-side hooks are oftenused to enforce certain policies, and these scripts aren't transferred during aclone. You can enforce policy on the server side to reject pushes of commitsthat don't conform to some policy, but it's entirely up to the developer to usethese scripts on the client side.

?

35.??You can set up threeclient-side hooks for an e-mail-based workflow. They're all invoked by the git am?command. If you're takingpatches over e-mail prepared by git format-patch, then some of thesemay be helpful to you. applypatch-msg takes a singleargument: the name of the temporary file that contains the proposed commitmessage. Git aborts the patch if this script exits non-zero. You can use thisto make sure a commit message is properly formatted or to normalize the messageby having the script edit it in place. pre-applypatch?takes no arguments and is run after the patch is applied, so you can use it toinspect the snapshot before making the commit. You can run tests or otherwiseinspect the working tree with this script. If something is missing or the testsdon't pass, exiting non-zero also aborts the git am script withoutcommitting the patch. You can use post-applypatch to notifya group or the author of the patch you pulled in that you've done so. You can'tstop the patching process with this script.

?

36.??The pre-rebase?hook runs before you rebase anything and can halt theprocess by exiting non-zero. You can use this hook to disallow rebasing anycommits that have already been pushed. The example pre-rebase hook that Gitinstalls does this, although it assumes that next is the name of thebranch you publish.

?

37.??After you run a successful gitcheckout, the post-checkout?hook runs; you can use it to set up your working directory properly for yourproject environment. This may mean moving in large binary files that you don'twant source controlled, auto-generating documentation, or something along thoselines.

?

38.??The post-merge hook runs after a successful mergecommand. You can use it to restore data in the working tree that Git can'ttrack, such as permissions data. This hook can likewise validate the presenceof files external to Git control that you may want copied in when the workingtree changes.

?

39.??pre-receivetakes a list of references that are beingpushed from stdin; if it exits non-zero, none of them are accepted. You canuse this hook to do things like make sure none of the updated references arenon-fast-forwards; or to check that the user doing the pushing has create,delete, or push access or access to push updates to all the files they'remodifying with the push.

?

40.??The post-receive?hook runs after the entire process is completed and canbe used to update other services or notify users. It takes the same stdindata as the pre-receive?hook. Thisscript can't stop the push process, but the client doesn't disconnect until ithas completed; so, be careful when you try to do anything that may take a longtime.

?

41.??The update hook is verysimilar to the pre-receive?hook, except that it's runonce for each branch the pusher is trying to update. If the pusher is trying topush to multiple branches, pre-receive runs only once, whereas update?runs once per branch they're pushing to. Instead ofreading from stdin, this script takes three arguments: the name of thereference (branch), the SHA-1 that reference pointed to before the push, andthe SHA-1 the user is trying to push. If the update script exitsnon-zero, only that reference is rejected; other references can still be updated.

?

42.??All the sample hook scriptsdistributed with Git are in either Perl or Bash scripting, so you can also seeplenty of examples of hooks in those languages by looking at the samples.

?

43.??git rev-list is basically the git log?command, but by default it prints out only the SHA-1 values and no otherinformation. So, to get a list of all the commit SHAs introduced between onecommit SHA and another, you can run something like this:

$ git rev-list 538c33..d14fc7

?

44.? To get the raw commit data, youcan use another plumbing command called gitcat-file:

$ git cat-file commit ca82a6

tree Cfda3bf379e4f8dba8717dee55aab78aef7f4daf

parent 085bb3bcb608ele8451d4b2432f8ecbe6306e7e7

author Scott Chacon <schacon@gmail.com> 1205815931 ?0700

committer Scott Chacon <schacon@gmail.com> 1240030591 ?0700

?

changed the version number

?

A simple way to get the commit messagefrom a commit when you have the SHA-1 value is to go to the first blank lineand take everything after that. You can do so with the sed command on Unixsystems:

$ git cat-file commit ca82a6 | sed '1,/^$/d'

changed the version number

?

45.??You can pretty easily see whatfiles have been modified in a single commit with the --name-only option to thegitlog command:

$ git log ?1 --name-only --pretty=format:'' 9f585d

?

README

lib/test.rb

?

46.??It's important to note thatanything your update hook script prints to stdout will betransferred to the client.

?

47.??Client-side hook scripts runfrom your working directory, while server-side hook scripts run from your Gitdirectory.

?

48.??The SHA^@?syntax resolves to all the parents of that commit.

git rev-list ^#{sha}^@ refs/remotes/#{remote_ref}

The above command is looking for any commit that isreachable from the last commit on the remote and that isn't reachable from anyparent of any of the SHAs.

热点排行