Merge branch 'jc/ll-merge-binary-ours'
authorJunio C Hamano <gitster@pobox.com>
Sat, 15 Sep 2012 04:39:56 +0000 (21:39 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 15 Sep 2012 04:39:56 +0000 (21:39 -0700)
"git merge -Xtheirs" did not help content-level merge of binary
files; it should just take their version. Also "*.jpg binary" in
the attributes did not imply they should use the binary ll-merge
driver.

* jc/ll-merge-binary-ours:
ll-merge: warn about inability to merge binary files only when we can't
attr: "binary" attribute should choose built-in "binary" merge driver
merge: teach -Xours/-Xtheirs to binary ll-merge driver

1  2 
Documentation/gitattributes.txt
attr.c
ll-merge.c
index e16f3e175bd8915d139961c649be209b0afc535f,ead72549227e504523dd4230f04a3865dc0e0c60..462b79c120ddb132bd125104240a488cc31f877b
@@@ -75,8 -75,6 +75,8 @@@ repositories (i.e., attributes of inter
  `.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.
  
@@@ -296,27 -294,16 +296,27 @@@ output is used to update the worktree f
  `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.
@@@ -348,16 -335,6 +348,16 @@@ input that is already correctly indente
  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:
@@@ -927,7 -904,7 +927,7 @@@ file at the toplevel (i.e. not in any s
  macro attribute "binary" is equivalent to:
  
  ------------
- [attr]binary -diff -text
+ [attr]binary -diff -merge -text
  ------------
  
  
diff --combined attr.c
index f12c83f80a0f03b2112c212e46c571ec4074abf3,3f581b3cec688aab9e93f6c83f579eef6f378488..3430faf2ccc5e11a9c04432b7a4f13160130e141
--- 1/attr.c
--- 2/attr.c
+++ b/attr.c
@@@ -306,7 -306,7 +306,7 @@@ static void free_attr_elem(struct attr_
  }
  
  static const char *builtin_attr[] = {
-       "[attr]binary -diff -text",
+       "[attr]binary -diff -merge -text",
        NULL,
  };
  
@@@ -352,11 -352,8 +352,11 @@@ static struct attr_stack *read_attr_fro
        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);
@@@ -500,7 -497,6 +500,7 @@@ static int git_attr_system(void
  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) {
diff --combined ll-merge.c
index f3f7692158666ffd2ab6f65f4040462e4a7d2d00,307315b7883db7dbaa8835e1cda72cdd7bdaae93..acea33bf1babfe541c319081f14625ac779bb582
@@@ -35,7 -35,7 +35,7 @@@ struct ll_merge_driver 
   */
  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,
@@@ -73,8 -91,6 +91,6 @@@
        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,