Add configuration option for default untracked files mode
[gitweb.git] / unpack-trees.c
index feae846226237fce9b4ff4a4810a9961637a4ca5..cba0aca062f201c5cd5f8799f2190d4a6f06e7c7 100644 (file)
@@ -8,6 +8,36 @@
 #include "progress.h"
 #include "refs.h"
 
+/*
+ * Error messages expected by scripts out of plumbing commands such as
+ * read-tree.  Non-scripted Porcelain is not required to use these messages
+ * and in fact are encouraged to reword them to better suit their particular
+ * situation better.  See how "git checkout" replaces not_uptodate_file to
+ * explain why it does not allow switching between branches when you have
+ * local changes, for example.
+ */
+static struct unpack_trees_error_msgs unpack_plumbing_errors = {
+       /* would_overwrite */
+       "Entry '%s' would be overwritten by merge. Cannot merge.",
+
+       /* not_uptodate_file */
+       "Entry '%s' not uptodate. Cannot merge.",
+
+       /* not_uptodate_dir */
+       "Updating '%s' would lose untracked files in it",
+
+       /* would_lose_untracked */
+       "Untracked working tree file '%s' would be %s by merge.",
+
+       /* bind_overlap */
+       "Entry '%s' overlaps with '%s'.  Cannot bind.",
+};
+
+#define ERRORMSG(o,fld) \
+       ( ((o) && (o)->msgs.fld) \
+       ? ((o)->msgs.fld) \
+       : (unpack_plumbing_errors.fld) )
+
 static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
        unsigned int set, unsigned int clear)
 {
@@ -26,11 +56,12 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
  * directories, in case this unlink is the removal of the
  * last entry in the directory -- empty directories are removed.
  */
-static void unlink_entry(char *name, char *last_symlink)
+static void unlink_entry(struct cache_entry *ce)
 {
        char *cp, *prev;
+       char *name = ce->name;
 
-       if (has_symlink_leading_path(name, last_symlink))
+       if (has_symlink_leading_path(ce_namelen(ce), ce->name))
                return;
        if (unlink(name))
                return;
@@ -58,7 +89,6 @@ static int check_updates(struct unpack_trees_options *o)
 {
        unsigned cnt = 0, total = 0;
        struct progress *progress = NULL;
-       char last_symlink[PATH_MAX];
        struct index_state *index = &o->result;
        int i;
        int errs = 0;
@@ -75,14 +105,13 @@ static int check_updates(struct unpack_trees_options *o)
                cnt = 0;
        }
 
-       *last_symlink = '\0';
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
 
                if (ce->ce_flags & CE_REMOVE) {
                        display_progress(progress, ++cnt);
                        if (o->update)
-                               unlink_entry(ce->name, last_symlink);
+                               unlink_entry(ce);
                        remove_index_entry_at(&o->result, i);
                        i--;
                        continue;
@@ -97,7 +126,6 @@ static int check_updates(struct unpack_trees_options *o)
                        ce->ce_flags &= ~CE_UPDATE;
                        if (o->update) {
                                errs |= checkout_entry(ce, &state, NULL);
-                               *last_symlink = '\0';
                        }
                }
        }
@@ -330,8 +358,13 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)
        return -1;
 }
 
+/*
+ * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the
+ * resulting index, -2 on failure to reflect the changes to the work tree.
+ */
 int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
 {
+       int ret;
        static struct cache_entry *dfc;
 
        if (len > MAX_UNPACK_TREES)
@@ -376,19 +409,17 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                return unpack_failed(o, "Merge requires file-level merging");
 
        o->src_index = NULL;
-       if (check_updates(o))
-               return -1;
+       ret = check_updates(o) ? (-2) : 0;
        if (o->dst_index)
                *o->dst_index = o->result;
-       return 0;
+       return ret;
 }
 
 /* Here come the merge functions */
 
-static int reject_merge(struct cache_entry *ce)
+static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)
 {
-       return error("Entry '%s' would be overwritten by merge. Cannot merge.",
-                    ce->name);
+       return error(ERRORMSG(o, would_overwrite), ce->name);
 }
 
 static int same(struct cache_entry *a, struct cache_entry *b)
@@ -432,7 +463,7 @@ static int verify_uptodate(struct cache_entry *ce,
        if (errno == ENOENT)
                return 0;
        return o->gently ? -1 :
-               error("Entry '%s' not uptodate. Cannot merge.", ce->name);
+               error(ERRORMSG(o, not_uptodate_file), ce->name);
 }
 
 static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
@@ -519,8 +550,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
        i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
        if (i)
                return o->gently ? -1 :
-                       error("Updating '%s' would lose untracked files in it",
-                             ce->name);
+                       error(ERRORMSG(o, not_uptodate_dir), ce->name);
        free(pathbuf);
        return cnt;
 }
@@ -553,7 +583,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
        if (o->index_only || o->reset || !o->update)
                return 0;
 
-       if (has_symlink_leading_path(ce->name, NULL))
+       if (has_symlink_leading_path(ce_namelen(ce), ce->name))
                return 0;
 
        if (!lstat(ce->name, &st)) {
@@ -620,8 +650,7 @@ static int verify_absent(struct cache_entry *ce, const char *action,
                }
 
                return o->gently ? -1 :
-                       error("Untracked working tree file '%s' "
-                             "would be %s by merge.", ce->name, action);
+                       error(ERRORMSG(o, would_lose_untracked), ce->name, action);
        }
        return 0;
 }
@@ -753,7 +782,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
        /* #14, #14ALT, #2ALT */
        if (remote && !df_conflict_head && head_match && !remote_match) {
                if (index && !same(index, remote) && !same(index, head))
-                       return o->gently ? -1 : reject_merge(index);
+                       return o->gently ? -1 : reject_merge(index, o);
                return merged_entry(remote, index, o);
        }
        /*
@@ -761,7 +790,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
         * make sure that it matches head.
         */
        if (index && !same(index, head))
-               return o->gently ? -1 : reject_merge(index);
+               return o->gently ? -1 : reject_merge(index, o);
 
        if (head) {
                /* #5ALT, #15 */
@@ -903,11 +932,11 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
                else {
                        /* all other failures */
                        if (oldtree)
-                               return o->gently ? -1 : reject_merge(oldtree);
+                               return o->gently ? -1 : reject_merge(oldtree, o);
                        if (current)
-                               return o->gently ? -1 : reject_merge(current);
+                               return o->gently ? -1 : reject_merge(current, o);
                        if (newtree)
-                               return o->gently ? -1 : reject_merge(newtree);
+                               return o->gently ? -1 : reject_merge(newtree, o);
                        return -1;
                }
        }
@@ -933,7 +962,7 @@ int bind_merge(struct cache_entry **src,
                             o->merge_size);
        if (a && old)
                return o->gently ? -1 :
-                       error("Entry '%s' overlaps with '%s'.  Cannot bind.", a->name, old->name);
+                       error(ERRORMSG(o, bind_overlap), a->name, old->name);
        if (!a)
                return keep_entry(old, o);
        else