`.gitattributes` files. Attributes that should affect all repositories
for a single user should be placed in a file specified by the
`core.attributesfile` configuration option (see linkgit:git-config[1]).
+Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
+is either not set or empty, $HOME/.config/git/attributes is used instead.
Attributes for all users on a system should be placed in the
`$(prefix)/etc/gitattributes` file.
`clean` command is used to convert the contents of worktree file
upon checkin.
-A missing filter driver definition in the config is not an error
-but makes the filter a no-op passthru.
+One use of the content filtering is to massage the content into a shape
+that is more convenient for the platform, filesystem, and the user to use.
+For this mode of operation, the key phrase here is "more convenient" and
+not "turning something unusable into usable". In other words, the intent
+is that if someone unsets the filter driver definition, or does not have
+the appropriate filter program, the project should still be usable.
-The content filtering is done to massage the content into a
-shape that is more convenient for the platform, filesystem, and
-the user to use. The key phrase here is "more convenient" and not
-"turning something unusable into usable". In other words, the
-intent is that if someone unsets the filter driver definition,
-or does not have the appropriate filter program, the project
-should still be usable.
+Another use of the content filtering is to store the content that cannot
+be directly used in the repository (e.g. a UUID that refers to the true
+content stored outside git, or an encrypted content) and turn it into a
+usable form upon checkout (e.g. download the external content, or decrypt
+the encrypted content).
+
+These two filters behave differently, and by default, a filter is taken as
+the former, massaging the contents into more convenient shape. A missing
+filter driver definition in the config, or a filter driver that exits with
+a non-zero status, is not an error but makes the filter a no-op passthru.
+
+You can declare that a filter turns a content that by itself is unusable
+into a usable content by setting the filter.<driver>.required configuration
+variable to `true`.
For example, in .gitattributes, you would assign the `filter`
attribute for paths.
smudge filter means that the clean filter _must_ accept its own output
without modifying it.
+If a filter _must_ succeed in order to make the stored contents usable,
+you can declare that the filter is `required`, in the configuration:
+
+------------------------
+[filter "crypt"]
+ clean = openssl enc ...
+ smudge = openssl enc -d ...
+ required
+------------------------
+
Sequence "%f" on the filter command line is replaced with the name of
the file the filter is working on. A filter might use this in keyword
substitution. For example:
macro attribute "binary" is equivalent to:
------------
- [attr]binary -diff -text
+ [attr]binary -diff -merge -text
------------
}
static const char *builtin_attr[] = {
- "[attr]binary -diff -text",
+ "[attr]binary -diff -merge -text",
NULL,
};
char buf[2048];
int lineno = 0;
- if (!fp)
+ if (!fp) {
+ if (errno != ENOENT)
+ warn_on_inaccessible(path);
return NULL;
+ }
res = xcalloc(1, sizeof(*res));
while (fgets(buf, sizeof(buf), fp))
handle_attr_line(res, buf, path, ++lineno, macro_ok);
static void bootstrap_attr_stack(void)
{
struct attr_stack *elem;
+ char *xdg_attributes_file;
if (attr_stack)
return;
}
}
+ if (!git_attributes_file) {
+ home_config_paths(NULL, &xdg_attributes_file, "attributes");
+ git_attributes_file = xdg_attributes_file;
+ }
if (git_attributes_file) {
elem = read_attr_from_file(git_attributes_file, 1);
if (elem) {
*/
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
mmbuffer_t *result,
- const char *path_unused,
+ const char *path,
mmfile_t *orig, const char *orig_name,
mmfile_t *src1, const char *name1,
mmfile_t *src2, const char *name2,
assert(opts);
/*
- * The tentative merge result is "ours" for the final round,
- * or common ancestor for an internal merge. Still return
- * "conflicted merge" status.
+ * The tentative merge result is the or common ancestor for an internal merge.
*/
- stolen = opts->virtual_ancestor ? orig : src1;
+ if (opts->virtual_ancestor) {
+ stolen = orig;
+ } else {
+ switch (opts->variant) {
+ default:
- warning("Cannot merge binary files: %s (%s vs. %s)\n",
++ warning("Cannot merge binary files: %s (%s vs. %s)",
+ path, name1, name2);
+ /* fallthru */
+ case XDL_MERGE_FAVOR_OURS:
+ stolen = src1;
+ break;
+ case XDL_MERGE_FAVOR_THEIRS:
+ stolen = src2;
+ break;
+ }
+ }
result->ptr = stolen->ptr;
result->size = stolen->size;
stolen->ptr = NULL;
- return 1;
+
+ /*
+ * With -Xtheirs or -Xours, we have cleanly merged;
+ * otherwise we got a conflict.
+ */
+ return (opts->variant ? 0 : 1);
}
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
if (buffer_is_binary(orig->ptr, orig->size) ||
buffer_is_binary(src1->ptr, src1->size) ||
buffer_is_binary(src2->ptr, src2->size)) {
- warning("Cannot merge binary files: %s (%s vs. %s)",
- path, name1, name2);
return ll_binary_merge(drv_unused, result,
path,
orig, orig_name,