Code

checkout: "best effort" checkout
authorJunio C Hamano <gitster@pobox.com>
Wed, 28 May 2008 22:26:59 +0000 (15:26 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 30 May 2008 00:35:22 +0000 (17:35 -0700)
When unpack_trees() returned an error while switching branches, we used to
stop right there, exiting without writing the index out or switching HEAD.

This is Ok when unpack_trees() returned an error because it detected
untracked files or locally modified paths that could be overwritten by
branch switching, because that error return is done before we start to
modify the work tree.  But it is undesirable if unpack_trees() already
started to update the work tree and a failure is returned because some but
not all paths are updated in the work tree, perhaps because a directory
that some files need to go in was read-only by mistake, or a file that
will be overwritten by branch switching had a mandatory lock on it and we
failed to unlink it.

This changes the behaviour upon such an error to complete the branch
switching; the files updated in the work tree will hopefully be much more
consistent with the index and HEAD derived from the switched-to branch.

We still issue error messages, and exit the command with non-zero status,
so scripted callers need to notice it.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin-checkout.c

index 9af5197b6060ce38c310d8b1f634c66e484ba1fc..93ea69bfaa083f49a6e808c7317ea1910b29c847 100644 (file)
@@ -155,6 +155,7 @@ struct checkout_opts {
        int quiet;
        int merge;
        int force;
+       int writeout_error;
 
        char *new_branch;
        int new_branch_log;
@@ -178,9 +179,20 @@ static int reset_tree(struct tree *tree, struct checkout_opts *o, int worktree)
        opts.dst_index = &the_index;
        parse_tree(tree);
        init_tree_desc(&tree_desc, tree->buffer, tree->size);
-       if (unpack_trees(1, &tree_desc, &opts))
+       switch (unpack_trees(1, &tree_desc, &opts)) {
+       case -2:
+               o->writeout_error = 1;
+               /*
+                * We return 0 nevertheless, as the index is all right
+                * and more importantly we have made best efforts to
+                * update paths in the work tree, and we cannot revert
+                * them.
+                */
+       case 0:
+               return 0;
+       default:
                return 128;
-       return 0;
+       }
 }
 
 struct branch_info {
@@ -243,7 +255,8 @@ static int merge_working_tree(struct checkout_opts *opts,
                tree = parse_tree_indirect(new->commit->object.sha1);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
 
-               if (unpack_trees(2, trees, &topts)) {
+               ret = unpack_trees(2, trees, &topts);
+               if (ret == -1) {
                        /*
                         * Unpack couldn't do a trivial merge; either
                         * give up or do a real merge, depending on
@@ -478,7 +491,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 
        update_refs_for_switch(opts, &old, new);
 
-       return post_checkout_hook(old.commit, new->commit, 1);
+       ret = post_checkout_hook(old.commit, new->commit, 1);
+       return ret || opts->writeout_error;
 }
 
 int cmd_checkout(int argc, const char **argv, const char *prefix)