static int find_first_merges(struct object_array *result, const char *path, struct commit *a, struct commit *b) { int i, j; struct object_array merges; struct commit *commit; int contains_another; char merged_revision[42]; const char *rev_args[] = { "rev-list", "--merges", "--ancestry-path", "--all", merged_revision, NULL }; struct rev_info revs; struct setup_revision_opt rev_opts; memset(&merges, 0, sizeof(merges)); memset(result, 0, sizeof(struct object_array)); memset(&rev_opts, 0, sizeof(rev_opts)); /* get all revisions that merge commit a */ snprintf(merged_revision, sizeof(merged_revision), "^%s", sha1_to_hex(a->object.sha1)); init_revisions(&revs, NULL); rev_opts.submodule = path; setup_revisions(sizeof(rev_args)/sizeof(char *)-1, rev_args, &revs, &rev_opts); /* save all revisions from the above list that contain b */ if (prepare_revision_walk(&revs)) die("revision walk setup failed"); while ((commit = get_revision(&revs)) != NULL) { struct object *o = &(commit->object); if (in_merge_bases(b, commit)) add_object_array(o, NULL, &merges); } reset_revision_walk(); /* Now we've got all merges that contain a and b. Prune all * merges that contain another found merge and save them in * result. */ for (i = 0; i < merges.nr; i++) { struct commit *m1 = (struct commit *) merges.objects[i].item; contains_another = 0; for (j = 0; j < merges.nr; j++) { struct commit *m2 = (struct commit *) merges.objects[j].item; if (i != j && in_merge_bases(m2, m1)) { contains_another = 1; break; } } if (!contains_another) add_object_array(merges.objects[i].item, merges.objects[i].name, result); } free(merges.objects); return result->nr; }
static int branch_merged(int kind, const char *name, struct commit *rev, struct commit *head_rev) { /* * This checks whether the merge bases of branch and HEAD (or * the other branch this branch builds upon) contains the * branch, which means that the branch has already been merged * safely to HEAD (or the other branch). */ struct commit *reference_rev = NULL; const char *reference_name = NULL; void *reference_name_to_free = NULL; int merged; if (kind == REF_LOCAL_BRANCH) { struct branch *branch = branch_get(name); unsigned char sha1[20]; if (branch && branch->merge && branch->merge[0] && branch->merge[0]->dst && (reference_name = reference_name_to_free = resolve_refdup(branch->merge[0]->dst, RESOLVE_REF_READING, sha1, NULL)) != NULL) reference_rev = lookup_commit_reference(sha1); } if (!reference_rev) reference_rev = head_rev; merged = in_merge_bases(rev, reference_rev); /* * After the safety valve is fully redefined to "check with * upstream, if any, otherwise with HEAD", we should just * return the result of the in_merge_bases() above without * any of the following code, but during the transition period, * a gentle reminder is in order. */ if ((head_rev != reference_rev) && in_merge_bases(rev, head_rev) != merged) { if (merged) warning(_("deleting branch '%s' that has been merged to\n" " '%s', but not yet merged to HEAD."), name, reference_name); else warning(_("not deleting branch '%s' that is not yet merged to\n" " '%s', even though it is merged to HEAD."), name, reference_name); } free(reference_name_to_free); return merged; }
static int verify_merge_base(struct object_id *head_oid, struct ref *remote) { struct commit *head = lookup_commit_or_die(head_oid, "HEAD"); struct commit *branch = lookup_commit_or_die(&remote->old_oid, remote->name); return in_merge_bases(branch, head); }
static int handle_is_ancestor(int argc, const char **argv) { struct commit *one, *two; if (argc != 2) die("--is-ancestor takes exactly two commits"); one = get_commit_reference(argv[0]); two = get_commit_reference(argv[1]); if (in_merge_bases(one, two)) return 0; else return 1; }
int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20], const unsigned char a[20], const unsigned char b[20]) { struct commit *commit_base, *commit_a, *commit_b; int parent_count; struct object_array merges; int i; /* store a in result in case we fail */ hashcpy(result, a); /* we can not handle deletion conflicts */ if (is_null_sha1(base)) return 0; if (is_null_sha1(a)) return 0; if (is_null_sha1(b)) return 0; if (add_submodule_odb(path)) { MERGE_WARNING(path, "not checked out"); return 0; } if (!(commit_base = lookup_commit_reference(base)) || !(commit_a = lookup_commit_reference(a)) || !(commit_b = lookup_commit_reference(b))) { MERGE_WARNING(path, "commits not present"); return 0; } /* check whether both changes are forward */ if (!in_merge_bases(commit_base, &commit_a, 1) || !in_merge_bases(commit_base, &commit_b, 1)) { MERGE_WARNING(path, "commits don't follow merge-base"); return 0; } /* Case #1: a is contained in b or vice versa */ if (in_merge_bases(commit_a, &commit_b, 1)) { hashcpy(result, b); return 1; } if (in_merge_bases(commit_b, &commit_a, 1)) { hashcpy(result, a); return 1; } /* * Case #2: There are one or more merges that contain a and b in * the submodule. If there is only one, then present it as a * suggestion to the user, but leave it marked unmerged so the * user needs to confirm the resolution. */ /* find commit which merges them */ parent_count = find_first_merges(&merges, path, commit_a, commit_b); switch (parent_count) { case 0: MERGE_WARNING(path, "merge following commits not found"); break; case 1: MERGE_WARNING(path, "not fast-forward"); fprintf(stderr, "Found a possible merge resolution " "for the submodule:\n"); print_commit((struct commit *) merges.objects[0].item); fprintf(stderr, "If this is correct simply add it to the index " "for example\n" "by using:\n\n" " git update-index --cacheinfo 160000 %s \"%s\"\n\n" "which will accept this suggestion.\n", sha1_to_hex(merges.objects[0].item->sha1), path); break; default: MERGE_WARNING(path, "multiple merges found"); for (i = 0; i < merges.nr; i++) print_commit((struct commit *) merges.objects[i].item); } free(merges.objects); return 0; }
static int delete_branches(int argc, const char **argv, int force, int kinds) { struct commit *rev, *head_rev = head_rev; unsigned char sha1[20]; char *name = NULL; const char *fmt, *remote; int i; int ret = 0; struct strbuf bname = STRBUF_INIT; switch (kinds) { case REF_REMOTE_BRANCH: fmt = "refs/remotes/%s"; remote = "remote "; force = 1; break; case REF_LOCAL_BRANCH: fmt = "refs/heads/%s"; remote = ""; break; default: die("cannot use -a with -d"); } if (!force) { head_rev = lookup_commit_reference(head_sha1); if (!head_rev) die("Couldn't look up commit object for HEAD"); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { int len = strlen(argv[i]); if (interpret_nth_last_branch(argv[i], &bname) != len) strbuf_add(&bname, argv[i], len); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error("Cannot delete the branch '%s' " "which you are currently on.", bname.buf); ret = 1; continue; } free(name); name = xstrdup(mkpath(fmt, bname.buf)); if (!resolve_ref(name, sha1, 1, NULL)) { error("%sbranch '%s' not found.", remote, bname.buf); ret = 1; continue; } rev = lookup_commit_reference(sha1); if (!rev) { error("Couldn't look up commit object for '%s'", name); ret = 1; continue; } /* This checks whether the merge bases of branch and * HEAD contains branch -- which means that the HEAD * contains everything in both. */ if (!force && !in_merge_bases(rev, &head_rev, 1)) { error("The branch '%s' is not an ancestor of " "your current HEAD.\n" "If you are sure you want to delete it, " "run 'git branch -D %s'.", bname.buf, bname.buf); ret = 1; continue; } if (delete_ref(name, sha1, 0)) { error("Error deleting %sbranch '%s'", remote, bname.buf); ret = 1; } else { struct strbuf buf = STRBUF_INIT; printf("Deleted %sbranch %s (%s).\n", remote, bname.buf, find_unique_abbrev(sha1, DEFAULT_ABBREV)); strbuf_addf(&buf, "branch.%s", bname.buf); if (git_config_rename_section(buf.buf, NULL) < 0) warning("Update of config-file failed"); strbuf_release(&buf); } } free(name); return(ret); }
static int update_local_ref(struct ref *ref, const char *remote, char *display) { struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); const char *pretty_ref = prettify_refname(ref->name); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); if (type < 0) die("object %s not found", sha1_to_hex(ref->new_sha1)); if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (verbosity > 0) sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH, "[up to date]", REFCOL_WIDTH, remote, pretty_ref); return 0; } if (current_branch && !strcmp(ref->name, current_branch->name) && !(update_head_ok || is_bare_repository()) && !is_null_sha1(ref->old_sha1)) { /* * If this is the head, and it's not okay to update * the head, and the old value of the head isn't empty... */ sprintf(display, "! %-*s %-*s -> %s (can't fetch in current branch)", TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, pretty_ref); return 1; } if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { int r; r = s_update_ref("updating tag", ref, 0); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', TRANSPORT_SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } current = lookup_commit_reference_gently(ref->old_sha1, 1); updated = lookup_commit_reference_gently(ref->new_sha1, 1); if (!current || !updated) { const char *msg; const char *what; int r; if (!strncmp(ref->name, "refs/tags/", 10)) { msg = "storing tag"; what = "[new tag]"; } else { msg = "storing head"; what = "[new branch]"; } r = s_update_ref(msg, ref, 0); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } if (in_merge_bases(current, &updated, 1)) { char quickref[83]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, ".."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); r = s_update_ref("fast-forward", ref, 1); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ', TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } else if (force || ref->force) { char quickref[84]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, "..."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); r = s_update_ref("forced-update", ref, 1); sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+', TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref, r ? "unable to update local ref" : "forced update"); return r; } else { sprintf(display, "! %-*s %-*s -> %s (non-fast-forward)", TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, pretty_ref); return 1; } }
static const char *update(struct command *cmd) { const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; const char *namespaced_name; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; struct ref_lock *lock; /* only refs/... are allowed */ if (prefixcmp(name, "refs/") || check_refname_format(name + 5, 0)) { rp_error("refusing to create funny ref '%s' remotely", name); return "funny refname"; } strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); if (is_ref_checked_out(namespaced_name)) { switch (deny_current_branch) { case DENY_IGNORE: break; case DENY_WARN: rp_warning("updating the current branch"); break; case DENY_REFUSE: case DENY_UNCONFIGURED: rp_error("refusing to update checked out branch: %s", name); if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; } } if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { error("unpack should have generated %s, " "but I can't find it!", sha1_to_hex(new_sha1)); return "bad pack"; } if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) { if (deny_deletes && !prefixcmp(name, "refs/heads/")) { rp_error("denying ref deletion for %s", name); return "deletion prohibited"; } if (!strcmp(namespaced_name, head_name)) { switch (deny_delete_current) { case DENY_IGNORE: break; case DENY_WARN: rp_warning("deleting the current branch"); break; case DENY_REFUSE: case DENY_UNCONFIGURED: if (deny_delete_current == DENY_UNCONFIGURED) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; } } } if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && !is_null_sha1(old_sha1) && !prefixcmp(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; old_object = parse_object(old_sha1); new_object = parse_object(new_sha1); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || new_object->type != OBJ_COMMIT) { error("bad sha1 objects for %s", name); return "bad ref"; } old_commit = (struct commit *)old_object; new_commit = (struct commit *)new_object; if (!in_merge_bases(old_commit, new_commit)) { rp_error("denying non-fast-forward %s" " (you should pull first)", name); return "non-fast-forward"; } } if (run_update_hook(cmd)) { rp_error("hook declined to update %s", name); return "hook declined"; } if (is_null_sha1(new_sha1)) { if (!parse_object(old_sha1)) { old_sha1 = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); } else { rp_warning("Deleting a non-existent ref."); cmd->did_not_exist = 1; } } if (delete_ref(namespaced_name, old_sha1, 0)) { rp_error("failed to delete %s", name); return "failed to delete"; } return NULL; /* good */ } else { lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0); if (!lock) { rp_error("failed to lock %s", name); return "failed to lock"; } if (write_ref_sha1(lock, new_sha1, "push")) { return "failed to write"; /* error() already called */ } return NULL; /* good */ } }
static const char *update(struct command *cmd, struct shallow_info *si) { const char *name = cmd->ref_name; struct strbuf namespaced_name_buf = STRBUF_INIT; const char *namespaced_name, *ret; unsigned char *old_sha1 = cmd->old_sha1; unsigned char *new_sha1 = cmd->new_sha1; /* only refs/... are allowed */ if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) { rp_error("refusing to create funny ref '%s' remotely", name); return "funny refname"; } strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name); namespaced_name = strbuf_detach(&namespaced_name_buf, NULL); if (is_ref_checked_out(namespaced_name)) { switch (deny_current_branch) { case DENY_IGNORE: break; case DENY_WARN: rp_warning("updating the current branch"); break; case DENY_REFUSE: case DENY_UNCONFIGURED: rp_error("refusing to update checked out branch: %s", name); if (deny_current_branch == DENY_UNCONFIGURED) refuse_unconfigured_deny(); return "branch is currently checked out"; case DENY_UPDATE_INSTEAD: ret = update_worktree(new_sha1); if (ret) return ret; break; } } if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { error("unpack should have generated %s, " "but I can't find it!", sha1_to_hex(new_sha1)); return "bad pack"; } if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) { if (deny_deletes && starts_with(name, "refs/heads/")) { rp_error("denying ref deletion for %s", name); return "deletion prohibited"; } if (head_name && !strcmp(namespaced_name, head_name)) { switch (deny_delete_current) { case DENY_IGNORE: break; case DENY_WARN: rp_warning("deleting the current branch"); break; case DENY_REFUSE: case DENY_UNCONFIGURED: case DENY_UPDATE_INSTEAD: if (deny_delete_current == DENY_UNCONFIGURED) refuse_unconfigured_deny_delete_current(); rp_error("refusing to delete the current branch: %s", name); return "deletion of the current branch prohibited"; default: return "Invalid denyDeleteCurrent setting"; } } } if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && !is_null_sha1(old_sha1) && starts_with(name, "refs/heads/")) { struct object *old_object, *new_object; struct commit *old_commit, *new_commit; old_object = parse_object(old_sha1); new_object = parse_object(new_sha1); if (!old_object || !new_object || old_object->type != OBJ_COMMIT || new_object->type != OBJ_COMMIT) { error("bad sha1 objects for %s", name); return "bad ref"; } old_commit = (struct commit *)old_object; new_commit = (struct commit *)new_object; if (!in_merge_bases(old_commit, new_commit)) { rp_error("denying non-fast-forward %s" " (you should pull first)", name); return "non-fast-forward"; } } if (run_update_hook(cmd)) { rp_error("hook declined to update %s", name); return "hook declined"; } if (is_null_sha1(new_sha1)) { struct strbuf err = STRBUF_INIT; if (!parse_object(old_sha1)) { old_sha1 = NULL; if (ref_exists(name)) { rp_warning("Allowing deletion of corrupt ref."); } else { rp_warning("Deleting a non-existent ref."); cmd->did_not_exist = 1; } } if (ref_transaction_delete(transaction, namespaced_name, old_sha1, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); return "failed to delete"; } strbuf_release(&err); return NULL; /* good */ } else { struct strbuf err = STRBUF_INIT; if (shallow_update && si->shallow_ref[cmd->index] && update_shallow_ref(cmd, si)) return "shallow error"; if (ref_transaction_update(transaction, namespaced_name, new_sha1, old_sha1, 0, "push", &err)) { rp_error("%s", err.buf); strbuf_release(&err); return "failed to update ref"; } strbuf_release(&err); return NULL; /* good */ } }
static struct commit *get_base_commit(const char *base_commit, struct commit **list, int total) { struct commit *base = NULL; struct commit **rev; int i = 0, rev_nr = 0; if (base_commit && strcmp(base_commit, "auto")) { base = lookup_commit_reference_by_name(base_commit); if (!base) die(_("Unknown commit %s"), base_commit); } else if ((base_commit && !strcmp(base_commit, "auto")) || base_auto) { struct branch *curr_branch = branch_get(NULL); const char *upstream = branch_get_upstream(curr_branch, NULL); if (upstream) { struct commit_list *base_list; struct commit *commit; unsigned char sha1[20]; if (get_sha1(upstream, sha1)) die(_("Failed to resolve '%s' as a valid ref."), upstream); commit = lookup_commit_or_die(sha1, "upstream base"); base_list = get_merge_bases_many(commit, total, list); /* There should be one and only one merge base. */ if (!base_list || base_list->next) die(_("Could not find exact merge base.")); base = base_list->item; free_commit_list(base_list); } else { die(_("Failed to get upstream, if you want to record base commit automatically,\n" "please use git branch --set-upstream-to to track a remote branch.\n" "Or you could specify base commit by --base=<base-commit-id> manually.")); } } ALLOC_ARRAY(rev, total); for (i = 0; i < total; i++) rev[i] = list[i]; rev_nr = total; /* * Get merge base through pair-wise computations * and store it in rev[0]. */ while (rev_nr > 1) { for (i = 0; i < rev_nr / 2; i++) { struct commit_list *merge_base; merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]); if (!merge_base || merge_base->next) die(_("Failed to find exact merge base")); rev[i] = merge_base->item; } if (rev_nr % 2) rev[i] = rev[2 * i]; rev_nr = (rev_nr + 1) / 2; } if (!in_merge_bases(base, rev[0])) die(_("base commit should be the ancestor of revision list")); for (i = 0; i < total; i++) { if (base == list[i]) die(_("base commit shouldn't be in revision list")); } free(rev); return base; }
void bitmap_writer_build(struct packing_data *to_pack) { static const double REUSE_BITMAP_THRESHOLD = 0.2; int i, reuse_after, need_reset; struct bitmap *base = bitmap_new(); struct rev_info revs; writer.bitmaps = kh_init_sha1(); writer.to_pack = to_pack; if (writer.show_progress) writer.progress = start_progress("Building bitmaps", writer.selected_nr); init_revisions(&revs, NULL); revs.tag_objects = 1; revs.tree_objects = 1; revs.blob_objects = 1; revs.no_walk = 0; revs.include_check = should_include; reset_revision_walk(); reuse_after = writer.selected_nr * REUSE_BITMAP_THRESHOLD; need_reset = 0; for (i = writer.selected_nr - 1; i >= 0; --i) { struct bitmapped_commit *stored; struct object *object; khiter_t hash_pos; int hash_ret; stored = &writer.selected[i]; object = (struct object *)stored->commit; if (stored->bitmap == NULL) { if (i < writer.selected_nr - 1 && (need_reset || !in_merge_bases(writer.selected[i + 1].commit, stored->commit))) { bitmap_reset(base); reset_all_seen(); } add_pending_object(&revs, object, ""); revs.include_check_data = base; if (prepare_revision_walk(&revs)) die("revision walk setup failed"); traverse_commit_list(&revs, show_commit, show_object, base); revs.pending.nr = 0; revs.pending.alloc = 0; revs.pending.objects = NULL; stored->bitmap = bitmap_to_ewah(base); need_reset = 0; } else need_reset = 1; if (i >= reuse_after) stored->flags |= BITMAP_FLAG_REUSE; hash_pos = kh_put_sha1(writer.bitmaps, object->sha1, &hash_ret); if (hash_ret == 0) die("Duplicate entry when writing index: %s", sha1_to_hex(object->sha1)); kh_value(writer.bitmaps, hash_pos) = stored; display_progress(writer.progress, writer.selected_nr - i); } bitmap_free(base); stop_progress(&writer.progress); compute_xor_offsets(); }