Merge branch 'jc/ll-merge-binary-ours' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 17 Oct 2012 17:26:51 +0000 (10:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Oct 2012 17:26:51 +0000 (10:26 -0700)
* 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 aff760ef7beefe81563f703c608dead93ce0704f,ead72549227e504523dd4230f04a3865dc0e0c60..52ab93d2c286d1f91fde8f14eaf6c3742443dcf2
@@@ -66,11 -66,6 +66,11 @@@ is from the path in question, the lowe
  global and system-wide files are considered (they have the lowest
  precedence).
  
 +When the `.gitattributes` file is missing from the work tree, the
 +path in the index is used as a fall-back.  During checkout process,
 +`.gitattributes` in the index is used and then the file in the
 +working tree is used as a fall-back.
 +
  If you wish to affect only a single repository (i.e., to assign
  attributes to files that are particular to
  one user's workflow for that repository), then
@@@ -80,8 -75,6 +80,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.
  
@@@ -301,27 -294,16 +301,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.
 +
 +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).
  
 -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.
 +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.
@@@ -353,16 -335,6 +353,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:
@@@ -932,7 -904,7 +932,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 056d702f6e244e4188abc3c8dc4db647699ec4d1,3f581b3cec688aab9e93f6c83f579eef6f378488..887a9ae46b7044489845abf2072339271caf2d4a
--- 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 && errno != ENOTDIR)
 +                      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,