Junio was working on a gitattributes system. Rather than be useful and write code, I wrote this document to show how an attribute system might work. The ideas in this document come primarily from the "unresolved issues" thread from the git mailing list. gmane/28388. In particular, from: - Brian Gernhardt - Johannes Schindelin - Junio Hamano - Linus Torvalds - Martin Waitz - Nicolas Pitre - Robin Rosenberg - Theodore Tso So they deserve the credit for the ideas, and I deserve the blame for the description. Signed-off-by: Andy Parkins <andyparkins@xxxxxxxxx> --- This one is better. I've included some of the points raised in the "unresolved issues" thread from January. Documentation/attributes.txt | 222 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 222 insertions(+), 0 deletions(-) create mode 100644 Documentation/attributes.txt diff --git a/Documentation/attributes.txt b/Documentation/attributes.txt new file mode 100644 index 0000000..9877786 --- /dev/null +++ b/Documentation/attributes.txt @@ -0,0 +1,222 @@ +Git Attributes System +===================== + +This document is a work-in-progress. It's only purpose is to assemble +attribute ideas into one place. + +== Attributes + +Individual paths are assigned attributes. Typically they will only have +one attribute, typically named after the corresponding mime type of that +file. However, it is not required that the attribute be a mime type nor +is it required that this be the only attribute. + +Attributes are attached to paths in one of two ways: + + - Via the .gitattributes file. This will work in the same way as the + .gitignore file. That is, there can be multiple .gitattributes files + throughout the working directory. + + Typically the .gitattributes file will be a version controlled file, + just like .gitignore. + + The format of this file will be similar to .gitignore. "#" starting + a comment. Globbing allowed. Paths to subdirectories allowed. Each + path will be followed by the list of attributes that applies to that + path. Additionally, we would probably want a way of disabling an + attribute. For example + + ------------------------------------- + # Sample .gitattributes file + *.png image/png + *.txt text/plain + *.c text/plain source-file + script/*.sh text/plain source-file + # Disable text/plain for a particular file + file-isnt-text-despite-extension.txt !text/plain + ------------------------------------- + + - Via the git configuration file system. i.e. /etc/gitconfig, + $HOME/.gitconfig and $GIT_DIR/config. + + This supplies the same facility as the .gitattributes file but allows + the attributes to be specifed out-of-tree. This will give the + advantage that standard attributes can be specified per-system via + /etc/gitconfig; per-user via $HOME/config or per-repository via + $GIT_DIR/config. + + It will obviously be of different format from the .gitattributes + file, but the attribute names and path specification will be + identical (and specified as if from the root of the repository tree). + For example: + + ------------------------------------ + [attributes "*.png"] + attribute = image/png + [attributes "*.c"] + attribute = text/plain + attribute = source-file + ------------------------------------ + + (This is pretty ugly, because of the "*" and "." in the section name, + however I can't think of another way of doing this without resorting to + just copying the format of the .gitattributes file; like + ------------------------------------- + [attributes] + path = *.png image/png + path = *.txt text/plain + path = *.c text/plain source-file + ------------------------------------- + but perhaps people would like that more?) + +With these two in place, attributes for files can be specified and +overridden easily. The priority of the various files will be (from +lowest to highest) + + - /etc/gitconfig + - $HOME/.gitconfig + - .gitattributes + - $GIT_DIR/config + +The $GIT_DIR/config file is highest priority so that a user can always +override an attribute that is in a .gitattributes managed by someone +else. + + +== Handlers + +At this point git would be in a position to answer the question "what +attributes does this file have?" for any file in the tree. + +The handler system will allow us to specify operations that should be +performed on files with particular attributes. For example, we might +want to have text files automatically filtered to match local line +ending conditions. + +---------------------------------------- +[handler "fix-line-endings"] + attribute = text/plain + infilter = eol_lf + outfilter = eol_local +---------------------------------------- + +This definition creates a handler named "fix-line-endings" (don't suppose +they actually need names) that would run the "eol_lf" filter on check +in, and the "eol_local" filter on checkout. + +Similarly, we might want to tell git-show how to show images: + +---------------------------------------- +[handler "show-images"] + attribute = image/png + attribute = image/jpeg + attribute = image/gif + prettyfilter = pipe display - +---------------------------------------- + +With this filter in place, +---------------------------------------- + $ git-show v1.0.0:images/picture.png +---------------------------------------- +Would run "display -" and pipe the picture to it. + +Multiple filters can be supplied, and order will be important. So, to +transparently decompress a file and fix the line endings for a text file +we might do: + +--------------------------------------- +[handler "decompress-text"] + attribute = compressed-text + infilter = gunzip + infilter = eol_lf + outfilter = eol_local + outfilter = gzip +--------------------------------------- + +This might be useful for documentation files that come compressed (like +README.gz used by Debian). + +Similarly, we might want to be able to look at compressed files stored +in the repository: + +--------------------------------------- +[handler "show-compressed-file"] + attribute = application/gzip + prettyfilter = gunzip + prettyfilter = eol_auto +--------------------------------------- + +=== Handler Types + + - infilter + Run by git-add when content is added to the repository. + - outfilter + Run by git-checkout or git-reset when copying content from the index + to the working directory. (Actually, more likely this would be done + at low level in git-read-tree) + - prettyfilter + Run by git-cat-file or git-show when content is being pretty-printed + for display to the user. If no prettyfilter is set, then it should + default to outfilter. + - merge + Git has built in, good support for merging standard text files. + However, if you wanted to add an external merge tool for merging, + say, XML files, you could supply it here + - diff + If you wanted to use an external diff for certain files, you would + specify it in in the diff handler + + + +=== Filter list + + - eol_lf + Force all line endings to line-feed. + + - eol_cr + Force all line endings to carriage-return. + + - eol_crlf + Force all line endings to carriage-return, line-feed. + + - eol_local + Force all line endings to local default (LF on UNIX; CRLF on Windows). + + - eol_auto + Do the "right thing" depending on the file content and local default. + + - pipe <cmd> + Open a bidirectional pipe and run <cmd>; which will transform the + file in whatever way one wishes. + + - keywords + The traditional CVS keywords are substituted in the file. Maybe: + $Id$, $Author$, $URL$, $Date$, $Rev$ + This filter would behave differently depending on whether it was an + infilter or an outfilter. On infilter it would remove the extra + information. On outfilter it would add the extra information. + + - gunzip, gzip / zip, unzip + Some files are stored compressed in their natural state (like ODF for + example). This isn't optimum for getting the best out of git. Git + (when making pack files) can store the delta between two files, and + compresses all objects in its store anyway. So, a compressed text + file that changes over time will actually take up more disk space + than the uncompressed file would take up. These compression filters + would fix that problem by transparently decompressing/compressing the + files on their way in and out. + + +== Problems + + - Initial Checkout + The .gitattributes file is not in the working directory, so how git + find out what to apply to a file? The potential solution might be to + use the in-repo .gitattributes for checking out; and the working-tree + .gitattributes when checking in. + - Merge of .gitattributes + What happens when .gitattributes conflicts during a merge? + - Change of .gitattributes without change of files. + What happens when .gitattributes changes, but the files that would be + affected by that change do not? Those files really should be checked + out again, to apply any new outfilter settings. -- 1.5.0.2.205.g74e20 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html