Make It Work: Global .gitattributes
Git is the vanguard of distributed VCSs, and as a matter of course, it provide a way to perform diff or merge on certain files while intermediately treating them as documents of a certain other format. By reflecting appropriate changes to configuration and attributes of git as described in "Git - Git Attributes," you can set up this intermediate conversion for files of your choice while in diff or merge process.
This is best described with an example. Say, there exists a file format called "property list" (hereinafter plist) in Mac, and it can come in 3 forms: XML, binary or JSON (it's not exactly JSON, but is similar to it). To perform diff or merge on files of this type in a consistent way, use command
plutil
provided by Mac OS X (or an open-source, GPL-licensed alternative libplist). Then take the following 2 steps.1. Changes to Git Configuration
git config --global diff.plist.textconv "plutil -convert xml1 -o -"This command sets up a diff driver named "plist" that intermediately converts input plist files of any format into ones of XML format. Replacing
diff.plist
into merge.plist
, you can set up a merge driver instead (be forewarned though, for conversion in merge is no longer intermediate, remember it changes file contents according to the conversion). --global
is optional; Per-user or per-repository basis, it's your call.2. Changes to Git Attributes
Git attributes can be defined like ".gitignore" file (BTW if interested, check my post: You need a .gitignore template? Try gitignore.io, It Rocks!), but I think that fact is not widely known because it's not mentioned in the official documents "Git - Git Configuration" or "Git - Git Attributes." But apparently, there were once a discussion about this global git attributes in the official git mailing list ([PATCH] Add global and system-wide gitattributes) and seemingly the final patch was merged into the source code trunk. Okay, here are 3 ways to set up git attributes;
For per-user basis:
echo "*.plist diff=plist" > ~/.gitattributes git config --global core.attributesfile "~/.gitattributes"
For per-repository basis without attributes file being placed under your project source tree:
echo "*.plist diff=plist" > ${your_repo}/.git/info/attributes
For per-path basis:
echo "*.plist diff=plist" > ${your_repo}/path/to/.gitattributes
*.plist
is a target file name pattern, and diff=plist
is a diff attribute that instructs git to use a diff driver named "plist" when it generates diff text of matching files. Like in Step 1, replacing diff
with merge
does the same for merge.Demo
If a plist file in your repository is binary and no diff/merge driver was specified, then diff text will look like below. Not informative.
contender-x% git diff
diff --git a/Info.plist b/Info.plist
index f38dced..9ea7d8e 100644
Binary files a/Info.plist and b/Info.plist differ
But if you follows the steps above, then diff text will look like below.
contender-x% git diff
diff --git a/Info.plist b/Info.plist
index f38dced..9ea7d8e 100644
--- a/Info.plist
+++ b/Info.plist
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
- <string>1.0.0</string>
+ <string>1.0.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
Depending on a diff/merge driver you set up, generated diff text changes. My example dealt with textual, sequential data like plist files, so diff text generation was simply done. But use of diff/merge driver for intermediate conversion can do more, such as generating diff text for audio, graphics, or arbitrarily structured data. Creating your own conversion tool for a diff/merge driver can be fun.
Comments
Post a Comment