static void deepen(int depth, int deepen_relative, struct object_array *shallows) { if (depth == INFINITE_DEPTH && !is_repository_shallow()) { int i; for (i = 0; i < shallows->nr; i++) { struct object *object = shallows->objects[i].item; object->flags |= NOT_SHALLOW; } } else if (deepen_relative) { struct object_array reachable_shallows = OBJECT_ARRAY_INIT; struct commit_list *result; get_reachable_list(shallows, &reachable_shallows); result = get_shallow_commits(&reachable_shallows, depth + 1, SHALLOW, NOT_SHALLOW); send_shallow(result); free_commit_list(result); object_array_clear(&reachable_shallows); } else { struct commit_list *result; result = get_shallow_commits(&want_obj, depth, SHALLOW, NOT_SHALLOW); send_shallow(result); free_commit_list(result); } send_unshallow(shallows); packet_flush(1); }
static int finish_automerge(struct commit *head, struct commit_list *common, unsigned char *result_tree, const char *wt_strategy) { struct commit_list *parents = NULL, *j; struct strbuf buf = STRBUF_INIT; unsigned char result_commit[20]; free_commit_list(common); if (allow_fast_forward) { parents = remoteheads; commit_list_insert(head, &parents); parents = reduce_heads(parents); } else { struct commit_list **pptr = &parents; pptr = &commit_list_insert(head, pptr)->next; for (j = remoteheads; j; j = j->next) pptr = &commit_list_insert(j->item, pptr)->next; } strbuf_addch(&merge_msg, '\n'); prepare_to_commit(); free_commit_list(remoteheads); if (commit_tree(&merge_msg, result_tree, parents, result_commit, NULL, sign_commit)) die(_("failed to write commit object")); strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(head, result_commit, buf.buf); strbuf_release(&buf); drop_save(); return 0; }
static int finish_automerge(struct commit_list *common, unsigned char *result_tree, const char *wt_strategy) { struct commit_list *parents = NULL, *j; struct strbuf buf = STRBUF_INIT; unsigned char result_commit[20]; free_commit_list(common); if (allow_fast_forward) { parents = remoteheads; commit_list_insert(lookup_commit(head), &parents); parents = reduce_heads(parents); } else { struct commit_list **pptr = &parents; pptr = &commit_list_insert(lookup_commit(head), pptr)->next; for (j = remoteheads; j; j = j->next) pptr = &commit_list_insert(j->item, pptr)->next; } free_commit_list(remoteheads); strbuf_addch(&merge_msg, '\n'); commit_tree(merge_msg.buf, result_tree, parents, result_commit); strbuf_addf(&buf, "Merge made by %s.", wt_strategy); finish(result_commit, buf.buf); strbuf_release(&buf); drop_save(); return 0; }
/* * "check_merge_bases" checks that merge bases are not "bad" (or "new"). * * - If one is "bad" (or "new"), it means the user assumed something wrong * and we must exit with a non 0 error code. * - If one is "good" (or "old"), that's good, we have nothing to do. * - If one is "skipped", we can't know but we should warn. * - If we don't know, we should check it out and ask the user to test. */ static void check_merge_bases(int no_checkout) { struct commit_list *result; int rev_nr; struct commit **rev = get_bad_and_good_commits(&rev_nr); result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1); for (; result; result = result->next) { const unsigned char *mb = result->item->object.sha1; if (!hashcmp(mb, current_bad_oid->hash)) { handle_bad_merge_base(); } else if (0 <= sha1_array_lookup(&good_revs, mb)) { continue; } else if (0 <= sha1_array_lookup(&skipped_revs, mb)) { handle_skipped_merge_base(mb); } else { printf("Bisecting: a merge base must be tested\n"); exit(bisect_checkout(mb, no_checkout)); } } free(rev); free_commit_list(result); }
static int cmd_log_walk(struct rev_info *rev) { struct commit *commit; if (rev->early_output) setup_early_output(rev); if (prepare_revision_walk(rev)) die("revision walk setup failed"); if (rev->early_output) finish_early_output(rev); /* * For --check and --exit-code, the exit code is based on CHECK_FAILED * and HAS_CHANGES being accumulated in rev->diffopt, so be careful to * retain that state information if replacing rev->diffopt in this loop */ while ((commit = get_revision(rev)) != NULL) { log_tree_commit(rev, commit); if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ free(commit->buffer); commit->buffer = NULL; } free_commit_list(commit->parents); commit->parents = NULL; } if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF && DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) { return 02; } return diff_result_code(&rev->diffopt, 0); }
static int cmd_log_walk(struct rev_info *rev) { struct commit *commit; if (rev->early_output) setup_early_output(rev); if (prepare_revision_walk(rev)) die("revision walk setup failed"); if (rev->early_output) finish_early_output(rev); while ((commit = get_revision(rev)) != NULL) { log_tree_commit(rev, commit); if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ free(commit->buffer); commit->buffer = NULL; } free_commit_list(commit->parents); commit->parents = NULL; } return 0; }
static int reachable(struct commit *want) { struct commit_list *work = NULL; commit_list_insert_by_date(want, &work); while (work) { struct commit_list *list = work->next; struct commit *commit = work->item; free(work); work = list; if (commit->object.flags & THEY_HAVE) { want->object.flags |= COMMON_KNOWN; break; } if (!commit->object.parsed) parse_object(commit->object.sha1); if (commit->object.flags & REACHABLE) continue; commit->object.flags |= REACHABLE; if (commit->date < oldest_have) continue; for (list = commit->parents; list; list = list->next) { struct commit *parent = list->item; if (!(parent->object.flags & REACHABLE)) commit_list_insert_by_date(parent, &work); } } want->object.flags |= REACHABLE; clear_commit_marks(want, REACHABLE); free_commit_list(work); return (want->object.flags & COMMON_KNOWN); }
static int finish_automerge(struct commit *head, int head_subsumed, struct commit_list *common, struct commit_list *remoteheads, unsigned char *result_tree, const char *wt_strategy) { struct commit_list *parents = NULL; struct strbuf buf = STRBUF_INIT; unsigned char result_commit[20]; free_commit_list(common); parents = remoteheads; if (!head_subsumed || !allow_fast_forward) commit_list_insert(head, &parents); strbuf_addch(&merge_msg, '\n'); prepare_to_commit(remoteheads); if (commit_tree(&merge_msg, result_tree, parents, result_commit, NULL, sign_commit)) die(_("failed to write commit object")); strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(head, remoteheads, result_commit, buf.buf); strbuf_release(&buf); drop_save(); return 0; }
int git_open_log(GIT_LOG * handle, char * arg) { struct rev_info *p_Rev; char ** argv=0; int argc=0; unsigned int i=0; struct setup_revision_opt opt; /* clear flags */ unsigned int obj_size = get_max_object_index(); for(i =0; i<obj_size; i++) { struct object *ob= get_indexed_object(i); if(ob) { ob->flags=0; if (ob->parsed && ob->type == OBJ_COMMIT) { struct commit* commit = (struct commit*)ob; free_commit_list(commit->parents); commit->parents = NULL; if (commit->tree) free_tree_buffer(commit->tree); commit->tree = NULL; ob->parsed = 0; } } } if(arg != NULL) argv = strtoargv(arg,&argc); if (!argv) return -1; p_Rev = malloc(sizeof(struct rev_info)); if (p_Rev == NULL) { free(argv); return -1; } memset(p_Rev,0,sizeof(struct rev_info)); invalidate_ref_cache(NULL); init_revisions(p_Rev, g_prefix); p_Rev->diff = 1; memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; cmd_log_init(argc, argv, g_prefix,p_Rev,&opt); p_Rev->pPrivate = argv; *handle = p_Rev; return 0; }
static void finish_commit(struct commit *commit, void *data) { if (commit->parents) { free_commit_list(commit->parents); commit->parents = NULL; } free_commit_buffer(commit); }
void free_commit_list(struct commit** commit_list) { if (*commit_list) { free_commit_list(&((*commit_list)->next)); free(*commit_list); } *commit_list = NULL; }
static int handle_fork_point(int argc, const char **argv) { unsigned char sha1[20]; char *refname; const char *commitname; struct rev_collect revs; struct commit *derived; struct commit_list *bases; int i, ret = 0; switch (dwim_ref(argv[0], strlen(argv[0]), sha1, &refname)) { case 0: die("No such ref: '%s'", argv[0]); case 1: break; /* good */ default: die("Ambiguous refname: '%s'", argv[0]); } commitname = (argc == 2) ? argv[1] : "HEAD"; if (get_sha1(commitname, sha1)) die("Not a valid object name: '%s'", commitname); derived = lookup_commit_reference(sha1); memset(&revs, 0, sizeof(revs)); revs.initial = 1; for_each_reflog_ent(refname, collect_one_reflog_ent, &revs); for (i = 0; i < revs.nr; i++) revs.commit[i]->object.flags &= ~TMP_MARK; bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit); /* * There should be one and only one merge base, when we found * a common ancestor among reflog entries. */ if (!bases || bases->next) { ret = 1; goto cleanup_return; } /* And the found one must be one of the reflog entries */ for (i = 0; i < revs.nr; i++) if (&bases->item->object == &revs.commit[i]->object) break; /* found */ if (revs.nr <= i) { ret = 1; /* not found */ goto cleanup_return; } printf("%s\n", oid_to_hex(&bases->item->object.oid)); cleanup_return: free_commit_list(bases); return ret; }
static void finish_commit(struct commit *commit) { if (commit->parents) { free_commit_list(commit->parents); commit->parents = NULL; } free(commit->buffer); commit->buffer = NULL; }
void simple_log_test(void) { struct commit* commit_list = NULL; int retval; retval = beargit_init(); CU_ASSERT(0==retval); FILE* asdf = fopen("asdf.txt", "w"); fclose(asdf); retval = beargit_add("asdf.txt"); CU_ASSERT(0==retval); run_commit(&commit_list, "GO BEARS!1"); run_commit(&commit_list, "GO BEARS!2"); run_commit(&commit_list, "GO BEARS!3"); retval = beargit_log(INT_MAX); CU_ASSERT(0==retval); struct commit* cur_commit = commit_list; const int LINE_SIZE = 512; char line[LINE_SIZE]; FILE* fstdout = fopen("TEST_STDOUT", "r"); CU_ASSERT_PTR_NOT_NULL(fstdout); while (cur_commit != NULL) { char refline[LINE_SIZE]; // First line is empty CU_ASSERT_PTR_NOT_NULL(fgets(line, LINE_SIZE, fstdout)); CU_ASSERT(!strcmp(line,"\n")); // Second line is commit -- don't check the ID. CU_ASSERT_PTR_NOT_NULL(fgets(line, LINE_SIZE, fstdout)); CU_ASSERT(!strncmp(line,"commit", strlen("commit"))); // Third line is msg sprintf(refline, " %s\n", cur_commit->msg); CU_ASSERT_PTR_NOT_NULL(fgets(line, LINE_SIZE, fstdout)); CU_ASSERT_STRING_EQUAL(line, refline); cur_commit = cur_commit->next; } // Last line is empty CU_ASSERT_PTR_NOT_NULL(fgets(line, LINE_SIZE, fstdout)); CU_ASSERT(!strcmp(line,"\n")); CU_ASSERT_PTR_NULL(fgets(line, LINE_SIZE, fstdout)); // It's the end of output CU_ASSERT(feof(fstdout)); fclose(fstdout); free_commit_list(&commit_list); }
static void deepen_by_rev_list(int ac, const char **av, struct object_array *shallows) { struct commit_list *result; result = get_shallow_commits_by_rev_list(ac, av, SHALLOW, NOT_SHALLOW); send_shallow(result); free_commit_list(result); send_unshallow(shallows); }
void cgit_print_atom(char *tip, char *path, int max_count) { char *host; const char *argv[] = {NULL, tip, NULL, NULL, NULL}; struct commit *commit; struct rev_info rev; int argc = 2; if (!tip) argv[1] = ctx.qry.head; if (path) { argv[argc++] = "--"; argv[argc++] = path; } init_revisions(&rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.verbose_header = 1; rev.show_root_diff = 0; rev.max_count = max_count; setup_revisions(argc, argv, &rev, NULL); prepare_revision_walk(&rev); host = cgit_hosturl(); ctx.page.mimetype = "text/xml"; ctx.page.charset = "utf-8"; cgit_print_http_headers(&ctx); html("<feed xmlns='http://www.w3.org/2005/Atom'>\n"); html("<title>"); html_txt(ctx.repo->name); html("</title>\n"); html("<subtitle>"); html_txt(ctx.repo->desc); html("</subtitle>\n"); if (host) { html("<link rel='alternate' type='text/html' href='http://"); html_attr(host); html_attr(cgit_repourl(ctx.repo->url)); html("'/>\n"); } while ((commit = get_revision(&rev)) != NULL) { add_entry(commit, host); free(commit->buffer); commit->buffer = NULL; free_commit_list(commit->parents); commit->parents = NULL; } html("</feed>\n"); }
/* * We pass blame from the current commit to its parents. We keep saying * "parent" (and "porigin"), but what we mean is to find scapegoat to * exonerate ourselves. */ static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit, int reverse) { if (!reverse) { if (revs->first_parent_only && commit->parents && commit->parents->next) { free_commit_list(commit->parents->next); commit->parents->next = NULL; } return commit->parents; } return lookup_decoration(&revs->children, &commit->object); }
/** * Sets merge_base to the octopus merge base of curr_head, merge_head and * fork_point. Returns 0 if a merge base is found, 1 otherwise. */ static int get_octopus_merge_base(struct object_id *merge_base, const struct object_id *curr_head, const struct object_id *merge_head, const struct object_id *fork_point) { struct commit_list *revs = NULL, *result; commit_list_insert(lookup_commit_reference(curr_head), &revs); commit_list_insert(lookup_commit_reference(merge_head), &revs); if (!is_null_oid(fork_point)) commit_list_insert(lookup_commit_reference(fork_point), &revs); result = get_octopus_merge_bases(revs); free_commit_list(revs); reduce_heads_replace(&result); if (!result) return 1; oidcpy(merge_base, &result->item->object.oid); free_commit_list(result); return 0; }
static int cmd_log_walk(struct rev_info *rev) { struct commit *commit; int saved_nrl = 0; int saved_dcctc = 0; if (rev->early_output) setup_early_output(rev); if (prepare_revision_walk(rev)) die(_("revision walk setup failed")); if (rev->early_output) finish_early_output(rev); /* * For --check and --exit-code, the exit code is based on CHECK_FAILED * and HAS_CHANGES being accumulated in rev->diffopt, so be careful to * retain that state information if replacing rev->diffopt in this loop */ while ((commit = get_revision(rev)) != NULL) { if (!log_tree_commit(rev, commit) && rev->max_count >= 0) /* * We decremented max_count in get_revision, * but we didn't actually show the commit. */ rev->max_count++; if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ free(commit->buffer); commit->buffer = NULL; } free_commit_list(commit->parents); commit->parents = NULL; if (saved_nrl < rev->diffopt.needed_rename_limit) saved_nrl = rev->diffopt.needed_rename_limit; if (rev->diffopt.degraded_cc_to_c) saved_dcctc = 1; } rev->diffopt.degraded_cc_to_c = saved_dcctc; rev->diffopt.needed_rename_limit = saved_nrl; if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF && DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) { return 02; } return diff_result_code(&rev->diffopt, 0); }
static void reflog_expiry_cleanup(void *cb_data) { struct expire_reflog_policy_cb *cb = cb_data; if (cb->unreachable_expire_kind != UE_ALWAYS) { if (cb->unreachable_expire_kind == UE_HEAD) { struct commit_list *elem; for (elem = cb->tips; elem; elem = elem->next) clear_commit_marks(elem->item, REACHABLE); free_commit_list(cb->tips); } else { clear_commit_marks(cb->tip_commit, REACHABLE); } } }
int git_free_commit(GIT_COMMIT *commit) { struct commit *p = commit->m_pGitCommit; if( p->parents) free_commit_list(p->parents); if( p->buffer ) { free(p->buffer); p->buffer=NULL; p->object.parsed=0; p->parents=0; p->tree=0; } memset(commit,0,sizeof(GIT_COMMIT)); return 0; }
static int show_merge_base(struct commit **rev, int rev_nr, int show_all) { struct commit_list *result, *r; result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1); if (!result) return 1; for (r = result; r; r = r->next) { printf("%s\n", oid_to_hex(&r->item->object.oid)); if (!show_all) break; } free_commit_list(result); return 0; }
static int handle_independent(int count, const char **args) { struct commit_list *revs = NULL, *rev; int i; for (i = count - 1; i >= 0; i--) commit_list_insert(get_commit_reference(args[i]), &revs); reduce_heads_replace(&revs); if (!revs) return 1; for (rev = revs; rev; rev = rev->next) printf("%s\n", oid_to_hex(&rev->item->object.oid)); free_commit_list(revs); return 0; }
/* Diff one or more commits. */ static int stdin_diff_commit(struct commit *commit, const char *p) { struct object_id oid; struct commit_list **pptr = NULL; /* Graft the fake parents locally to the commit */ while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) { struct commit *parent = lookup_commit(&oid); if (!pptr) { /* Free the real parent list */ free_commit_list(commit->parents); commit->parents = NULL; pptr = &(commit->parents); } if (parent) { pptr = &commit_list_insert(parent, pptr)->next; } } return log_tree_commit(&log_tree_opt, commit); }
/** * Sets merge_base to the octopus merge base of curr_head, merge_head and * fork_point. Returns 0 if a merge base is found, 1 otherwise. */ static int get_octopus_merge_base(unsigned char *merge_base, const unsigned char *curr_head, const unsigned char *merge_head, const unsigned char *fork_point) { struct commit_list *revs = NULL, *result; commit_list_insert(lookup_commit_reference(curr_head), &revs); commit_list_insert(lookup_commit_reference(merge_head), &revs); if (!is_null_sha1(fork_point)) commit_list_insert(lookup_commit_reference(fork_point), &revs); result = reduce_heads(get_octopus_merge_bases(revs)); free_commit_list(revs); if (!result) return 1; hashcpy(merge_base, result->item->object.oid.hash); return 0; }
commit_list parse_commit_list(FILE *f) { struct commit_node *root, *n; int ind = 0; root = NULL; n = new_commit_node(ind++, NULL, NULL); while (parse_commit(n, f) == 1) { if (!root) root = n; if (n->prev) n->prev->next = n; n = new_commit_node(ind++, n, NULL); } if (n->prev) n->prev->next = NULL; free_commit_list(&n); return root; }
/* Walk the commit DAG and collect number of commits per author per * timeperiod into a nested string_list collection. */ static struct string_list collect_stats(const struct cgit_period *period) { struct string_list authors; struct rev_info rev; struct commit *commit; const char *argv[] = {NULL, ctx.qry.head, NULL, NULL, NULL, NULL}; int argc = 3; time_t now; long i; struct tm *tm; char tmp[11]; time(&now); tm = gmtime(&now); period->trunc(tm); for (i = 1; i < period->count; i++) period->dec(tm); strftime(tmp, sizeof(tmp), "%Y-%m-%d", tm); argv[2] = xstrdup(fmt("--since=%s", tmp)); if (ctx.qry.path) { argv[3] = "--"; argv[4] = ctx.qry.path; argc += 2; } init_revisions(&rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.commit_format = CMIT_FMT_DEFAULT; rev.max_parents = 1; rev.verbose_header = 1; rev.show_root_diff = 0; setup_revisions(argc, argv, &rev, NULL); prepare_revision_walk(&rev); memset(&authors, 0, sizeof(authors)); while ((commit = get_revision(&rev)) != NULL) { add_commit(&authors, commit, period); free_commit_buffer(commit); free_commit_list(commit->parents); commit->parents = NULL; } return authors; }
static void create_boundary_commit_list(struct rev_info *revs) { unsigned i; struct commit *c; struct object_array *array = &revs->boundary_commits; struct object_array_entry *objects = array->objects; /* * If revs->commits is non-NULL at this point, an error occurred in * get_revision_1(). Ignore the error and continue printing the * boundary commits anyway. (This is what the code has always * done.) */ if (revs->commits) { free_commit_list(revs->commits); revs->commits = NULL; } /* * Put all of the actual boundary commits from revs->boundary_commits * into revs->commits */ for (i = 0; i < array->nr; i++) { c = (struct commit *)(objects[i].item); if (!c) continue; if (!(c->object.flags & CHILD_SHOWN)) continue; if (c->object.flags & (SHOWN | BOUNDARY)) continue; c->object.flags |= BOUNDARY; commit_list_insert(c, &revs->commits); } /* * If revs->topo_order is set, sort the boundary commits * in topological order */ sort_in_topological_order(&revs->commits, revs->lifo); }
int git_free_commit(GIT_COMMIT *commit) { struct commit *p = commit->m_pGitCommit; if( p->parents) free_commit_list(p->parents); if (p->maybe_tree) free_tree_buffer(p->maybe_tree); #pragma warning(push) #pragma warning(disable: 4090) free(commit->buffer); #pragma warning(pop) p->object.parsed = 0; p->parents = 0; p->maybe_tree = NULL; memset(commit,0,sizeof(GIT_COMMIT)); return 0; }
static void prepare_show_merge(struct rev_info *revs) { struct commit_list *bases; struct commit *head, *other; unsigned char sha1[20]; const char **prune = NULL; int i, prune_num = 1; /* counting terminating NULL */ if (get_sha1("HEAD", sha1) || !(head = lookup_commit(sha1))) die("--merge without HEAD?"); if (get_sha1("MERGE_HEAD", sha1) || !(other = lookup_commit(sha1))) die("--merge without MERGE_HEAD?"); add_pending_object(revs, &head->object, "HEAD"); add_pending_object(revs, &other->object, "MERGE_HEAD"); bases = get_merge_bases(head, other, 1); add_pending_commit_list(revs, bases, UNINTERESTING); free_commit_list(bases); head->object.flags |= SYMMETRIC_LEFT; if (!active_nr) read_cache(); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; if (ce_path_match(ce, revs->prune_data)) { prune_num++; prune = xrealloc(prune, sizeof(*prune) * prune_num); prune[prune_num-2] = ce->name; prune[prune_num-1] = NULL; } while ((i+1 < active_nr) && ce_same_name(ce, active_cache[i+1])) i++; } revs->prune_data = prune; revs->limited = 1; }