submodule.con commit Implement automatic fast-forward merge for submodules (68d03e4)
   1#include "cache.h"
   2#include "submodule.h"
   3#include "dir.h"
   4#include "diff.h"
   5#include "commit.h"
   6#include "revision.h"
   7#include "run-command.h"
   8#include "diffcore.h"
   9#include "refs.h"
  10
  11static int add_submodule_odb(const char *path)
  12{
  13        struct strbuf objects_directory = STRBUF_INIT;
  14        struct alternate_object_database *alt_odb;
  15        int ret = 0;
  16        const char *git_dir;
  17
  18        strbuf_addf(&objects_directory, "%s/.git", path);
  19        git_dir = read_gitfile_gently(objects_directory.buf);
  20        if (git_dir) {
  21                strbuf_reset(&objects_directory);
  22                strbuf_addstr(&objects_directory, git_dir);
  23        }
  24        strbuf_addstr(&objects_directory, "/objects/");
  25        if (!is_directory(objects_directory.buf)) {
  26                ret = -1;
  27                goto done;
  28        }
  29        /* avoid adding it twice */
  30        for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next)
  31                if (alt_odb->name - alt_odb->base == objects_directory.len &&
  32                                !strncmp(alt_odb->base, objects_directory.buf,
  33                                        objects_directory.len))
  34                        goto done;
  35
  36        alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
  37        alt_odb->next = alt_odb_list;
  38        strcpy(alt_odb->base, objects_directory.buf);
  39        alt_odb->name = alt_odb->base + objects_directory.len;
  40        alt_odb->name[2] = '/';
  41        alt_odb->name[40] = '\0';
  42        alt_odb->name[41] = '\0';
  43        alt_odb_list = alt_odb;
  44        prepare_alt_odb();
  45done:
  46        strbuf_release(&objects_directory);
  47        return ret;
  48}
  49
  50void handle_ignore_submodules_arg(struct diff_options *diffopt,
  51                                  const char *arg)
  52{
  53        if (!strcmp(arg, "all"))
  54                DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
  55        else if (!strcmp(arg, "untracked"))
  56                DIFF_OPT_SET(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
  57        else if (!strcmp(arg, "dirty"))
  58                DIFF_OPT_SET(diffopt, IGNORE_DIRTY_SUBMODULES);
  59        else
  60                die("bad --ignore-submodules argument: %s", arg);
  61}
  62
  63void show_submodule_summary(FILE *f, const char *path,
  64                unsigned char one[20], unsigned char two[20],
  65                unsigned dirty_submodule,
  66                const char *del, const char *add, const char *reset)
  67{
  68        struct rev_info rev;
  69        struct commit *commit, *left = left, *right = right;
  70        struct commit_list *merge_bases, *list;
  71        const char *message = NULL;
  72        struct strbuf sb = STRBUF_INIT;
  73        static const char *format = "  %m %s";
  74        int fast_forward = 0, fast_backward = 0;
  75
  76        if (is_null_sha1(two))
  77                message = "(submodule deleted)";
  78        else if (add_submodule_odb(path))
  79                message = "(not checked out)";
  80        else if (is_null_sha1(one))
  81                message = "(new submodule)";
  82        else if (!(left = lookup_commit_reference(one)) ||
  83                 !(right = lookup_commit_reference(two)))
  84                message = "(commits not present)";
  85
  86        if (!message) {
  87                init_revisions(&rev, NULL);
  88                setup_revisions(0, NULL, &rev, NULL);
  89                rev.left_right = 1;
  90                rev.first_parent_only = 1;
  91                left->object.flags |= SYMMETRIC_LEFT;
  92                add_pending_object(&rev, &left->object, path);
  93                add_pending_object(&rev, &right->object, path);
  94                merge_bases = get_merge_bases(left, right, 1);
  95                if (merge_bases) {
  96                        if (merge_bases->item == left)
  97                                fast_forward = 1;
  98                        else if (merge_bases->item == right)
  99                                fast_backward = 1;
 100                }
 101                for (list = merge_bases; list; list = list->next) {
 102                        list->item->object.flags |= UNINTERESTING;
 103                        add_pending_object(&rev, &list->item->object,
 104                                sha1_to_hex(list->item->object.sha1));
 105                }
 106                if (prepare_revision_walk(&rev))
 107                        message = "(revision walker failed)";
 108        }
 109
 110        if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
 111                fprintf(f, "Submodule %s contains untracked content\n", path);
 112        if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
 113                fprintf(f, "Submodule %s contains modified content\n", path);
 114
 115        if (!hashcmp(one, two)) {
 116                strbuf_release(&sb);
 117                return;
 118        }
 119
 120        strbuf_addf(&sb, "Submodule %s %s..", path,
 121                        find_unique_abbrev(one, DEFAULT_ABBREV));
 122        if (!fast_backward && !fast_forward)
 123                strbuf_addch(&sb, '.');
 124        strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV));
 125        if (message)
 126                strbuf_addf(&sb, " %s\n", message);
 127        else
 128                strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
 129        fwrite(sb.buf, sb.len, 1, f);
 130
 131        if (!message) {
 132                while ((commit = get_revision(&rev))) {
 133                        struct pretty_print_context ctx = {0};
 134                        ctx.date_mode = rev.date_mode;
 135                        strbuf_setlen(&sb, 0);
 136                        if (commit->object.flags & SYMMETRIC_LEFT) {
 137                                if (del)
 138                                        strbuf_addstr(&sb, del);
 139                        }
 140                        else if (add)
 141                                strbuf_addstr(&sb, add);
 142                        format_commit_message(commit, format, &sb, &ctx);
 143                        if (reset)
 144                                strbuf_addstr(&sb, reset);
 145                        strbuf_addch(&sb, '\n');
 146                        fprintf(f, "%s", sb.buf);
 147                }
 148                clear_commit_marks(left, ~0);
 149                clear_commit_marks(right, ~0);
 150        }
 151        strbuf_release(&sb);
 152}
 153
 154unsigned is_submodule_modified(const char *path, int ignore_untracked)
 155{
 156        ssize_t len;
 157        struct child_process cp;
 158        const char *argv[] = {
 159                "status",
 160                "--porcelain",
 161                NULL,
 162                NULL,
 163        };
 164        struct strbuf buf = STRBUF_INIT;
 165        unsigned dirty_submodule = 0;
 166        const char *line, *next_line;
 167        const char *git_dir;
 168
 169        strbuf_addf(&buf, "%s/.git", path);
 170        git_dir = read_gitfile_gently(buf.buf);
 171        if (!git_dir)
 172                git_dir = buf.buf;
 173        if (!is_directory(git_dir)) {
 174                strbuf_release(&buf);
 175                /* The submodule is not checked out, so it is not modified */
 176                return 0;
 177
 178        }
 179        strbuf_reset(&buf);
 180
 181        if (ignore_untracked)
 182                argv[2] = "-uno";
 183
 184        memset(&cp, 0, sizeof(cp));
 185        cp.argv = argv;
 186        cp.env = local_repo_env;
 187        cp.git_cmd = 1;
 188        cp.no_stdin = 1;
 189        cp.out = -1;
 190        cp.dir = path;
 191        if (start_command(&cp))
 192                die("Could not run git status --porcelain");
 193
 194        len = strbuf_read(&buf, cp.out, 1024);
 195        line = buf.buf;
 196        while (len > 2) {
 197                if ((line[0] == '?') && (line[1] == '?')) {
 198                        dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
 199                        if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
 200                                break;
 201                } else {
 202                        dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
 203                        if (ignore_untracked ||
 204                            (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED))
 205                                break;
 206                }
 207                next_line = strchr(line, '\n');
 208                if (!next_line)
 209                        break;
 210                next_line++;
 211                len -= (next_line - line);
 212                line = next_line;
 213        }
 214        close(cp.out);
 215
 216        if (finish_command(&cp))
 217                die("git status --porcelain failed");
 218
 219        strbuf_release(&buf);
 220        return dirty_submodule;
 221}
 222
 223static int find_first_merges(struct object_array *result, const char *path,
 224                struct commit *a, struct commit *b)
 225{
 226        int i, j;
 227        struct object_array merges;
 228        struct commit *commit;
 229        int contains_another;
 230
 231        char merged_revision[42];
 232        const char *rev_args[] = { "rev-list", "--merges", "--ancestry-path",
 233                                   "--all", merged_revision, NULL };
 234        struct rev_info revs;
 235        struct setup_revision_opt rev_opts;
 236
 237        memset(&merges, 0, sizeof(merges));
 238        memset(result, 0, sizeof(struct object_array));
 239        memset(&rev_opts, 0, sizeof(rev_opts));
 240
 241        /* get all revisions that merge commit a */
 242        snprintf(merged_revision, sizeof(merged_revision), "^%s",
 243                        sha1_to_hex(a->object.sha1));
 244        init_revisions(&revs, NULL);
 245        rev_opts.submodule = path;
 246        setup_revisions(sizeof(rev_args)/sizeof(char *)-1, rev_args, &revs, &rev_opts);
 247
 248        /* save all revisions from the above list that contain b */
 249        if (prepare_revision_walk(&revs))
 250                die("revision walk setup failed");
 251        while ((commit = get_revision(&revs)) != NULL) {
 252                struct object *o = &(commit->object);
 253                if (in_merge_bases(b, &commit, 1))
 254                        add_object_array(o, NULL, &merges);
 255        }
 256
 257        /* Now we've got all merges that contain a and b. Prune all
 258         * merges that contain another found merge and save them in
 259         * result.
 260         */
 261        for (i = 0; i < merges.nr; i++) {
 262                struct commit *m1 = (struct commit *) merges.objects[i].item;
 263
 264                contains_another = 0;
 265                for (j = 0; j < merges.nr; j++) {
 266                        struct commit *m2 = (struct commit *) merges.objects[j].item;
 267                        if (i != j && in_merge_bases(m2, &m1, 1)) {
 268                                contains_another = 1;
 269                                break;
 270                        }
 271                }
 272
 273                if (!contains_another)
 274                        add_object_array(merges.objects[i].item,
 275                                         merges.objects[i].name, result);
 276        }
 277
 278        free(merges.objects);
 279        return result->nr;
 280}
 281
 282static void print_commit(struct commit *commit)
 283{
 284        struct strbuf sb = STRBUF_INIT;
 285        struct pretty_print_context ctx = {0};
 286        ctx.date_mode = DATE_NORMAL;
 287        format_commit_message(commit, " %h: %m %s", &sb, &ctx);
 288        fprintf(stderr, "%s\n", sb.buf);
 289        strbuf_release(&sb);
 290}
 291
 292#define MERGE_WARNING(path, msg) \
 293        warning("Failed to merge submodule %s (%s)", path, msg);
 294
 295int merge_submodule(unsigned char result[20], const char *path,
 296                    const unsigned char base[20], const unsigned char a[20],
 297                    const unsigned char b[20])
 298{
 299        struct commit *commit_base, *commit_a, *commit_b;
 300        int parent_count;
 301        struct object_array merges;
 302
 303        int i;
 304
 305        /* store a in result in case we fail */
 306        hashcpy(result, a);
 307
 308        /* we can not handle deletion conflicts */
 309        if (is_null_sha1(base))
 310                return 0;
 311        if (is_null_sha1(a))
 312                return 0;
 313        if (is_null_sha1(b))
 314                return 0;
 315
 316        if (add_submodule_odb(path)) {
 317                MERGE_WARNING(path, "not checked out");
 318                return 0;
 319        }
 320
 321        if (!(commit_base = lookup_commit_reference(base)) ||
 322            !(commit_a = lookup_commit_reference(a)) ||
 323            !(commit_b = lookup_commit_reference(b))) {
 324                MERGE_WARNING(path, "commits not present");
 325                return 0;
 326        }
 327
 328        /* check whether both changes are forward */
 329        if (!in_merge_bases(commit_base, &commit_a, 1) ||
 330            !in_merge_bases(commit_base, &commit_b, 1)) {
 331                MERGE_WARNING(path, "commits don't follow merge-base");
 332                return 0;
 333        }
 334
 335        /* Case #1: a is contained in b or vice versa */
 336        if (in_merge_bases(commit_a, &commit_b, 1)) {
 337                hashcpy(result, b);
 338                return 1;
 339        }
 340        if (in_merge_bases(commit_b, &commit_a, 1)) {
 341                hashcpy(result, a);
 342                return 1;
 343        }
 344
 345        /*
 346         * Case #2: There are one or more merges that contain a and b in
 347         * the submodule. If there is only one, then present it as a
 348         * suggestion to the user, but leave it marked unmerged so the
 349         * user needs to confirm the resolution.
 350         */
 351
 352        /* find commit which merges them */
 353        parent_count = find_first_merges(&merges, path, commit_a, commit_b);
 354        switch (parent_count) {
 355        case 0:
 356                MERGE_WARNING(path, "merge following commits not found");
 357                break;
 358
 359        case 1:
 360                MERGE_WARNING(path, "not fast-forward");
 361                fprintf(stderr, "Found a possible merge resolution "
 362                                "for the submodule:\n");
 363                print_commit((struct commit *) merges.objects[0].item);
 364                fprintf(stderr,
 365                        "If this is correct simply add it to the index "
 366                        "for example\n"
 367                        "by using:\n\n"
 368                        "  git update-index --cacheinfo 160000 %s \"%s\"\n\n"
 369                        "which will accept this suggestion.\n",
 370                        sha1_to_hex(merges.objects[0].item->sha1), path);
 371                break;
 372
 373        default:
 374                MERGE_WARNING(path, "multiple merges found");
 375                for (i = 0; i < merges.nr; i++)
 376                        print_commit((struct commit *) merges.objects[i].item);
 377        }
 378
 379        free(merges.objects);
 380        return 0;
 381}