static int walk_revs_populate_todo(struct todo_list *todo_list, struct replay_opts *opts) { enum todo_command command = opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT; const char *command_string = todo_command_strings[command]; struct commit *commit; if (prepare_revs(opts)) return -1; while ((commit = get_revision(opts->revs))) { struct todo_item *item = append_new_todo(todo_list); const char *commit_buffer = get_commit_buffer(commit, NULL); const char *subject; int subject_len; item->command = command; item->commit = commit; item->arg = NULL; item->arg_len = 0; item->offset_in_buf = todo_list->buf.len; subject_len = find_commit_subject(commit_buffer, &subject); strbuf_addf(&todo_list->buf, "%s %s %.*s\n", command_string, short_commit_name(commit), subject_len, subject); unuse_commit_buffer(commit, commit_buffer); } return 0; }
static int fsck_commit(struct commit *commit, fsck_error error_func) { const char *buffer = get_commit_buffer(commit, NULL); int ret = fsck_commit_buffer(commit, buffer, error_func); unuse_commit_buffer(commit, buffer); return ret; }
static void record_person(int which, struct string_list *people, struct commit *commit) { const char *buffer; char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field; field = (which == 'a') ? "\nauthor " : "\ncommitter "; buffer = get_commit_buffer(commit, NULL); name = strstr(buffer, field); if (!name) return; name += strlen(field); name_end = strchrnul(name, '<'); if (*name_end) name_end--; while (isspace(*name_end) && name <= name_end) name_end--; if (name_end < name) return; name_buf = xmemdupz(name, name_end - name + 1); unuse_commit_buffer(commit, buffer); elem = string_list_lookup(people, name_buf); if (!elem) { elem = string_list_insert(people, name_buf); elem->util = (void *)0; } elem->util = (void*)(util_as_integral(elem) + 1); free(name_buf); }
static int fsck_commit(struct commit *commit, const char *data, unsigned long size, struct fsck_options *options) { const char *buffer = data ? data : get_commit_buffer(commit, &size); int ret = fsck_commit_buffer(commit, buffer, size, options); if (!data) unuse_commit_buffer(commit, buffer); return ret; }
static int create_graft(int argc, const char **argv, int force, int gentle) { struct object_id old_oid, new_oid; const char *old_ref = argv[0]; struct commit *commit; struct strbuf buf = STRBUF_INIT; const char *buffer; unsigned long size; if (get_oid(old_ref, &old_oid) < 0) return error(_("Not a valid object name: '%s'"), old_ref); commit = lookup_commit_reference(&old_oid); if (!commit) return error(_("could not parse %s"), old_ref); buffer = get_commit_buffer(commit, &size); strbuf_add(&buf, buffer, size); unuse_commit_buffer(commit, buffer); if (replace_parents(&buf, argc - 1, &argv[1]) < 0) { strbuf_release(&buf); return -1; } if (remove_signature(&buf)) { warning(_("the original commit '%s' has a gpg signature."), old_ref); warning(_("the signature will be removed in the replacement commit!")); } if (check_mergetags(commit, argc, argv)) { strbuf_release(&buf); return -1; } if (write_object_file(buf.buf, buf.len, commit_type, &new_oid)) { strbuf_release(&buf); return error(_("could not write replacement commit for: '%s'"), old_ref); } strbuf_release(&buf); if (!oidcmp(&old_oid, &new_oid)) { if (gentle) { warning("graft for '%s' unnecessary", oid_to_hex(&old_oid)); return 0; } return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid)); } return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force); }
static int format_todo(struct strbuf *buf, struct commit_list *todo_list, struct replay_opts *opts) { struct commit_list *cur = NULL; const char *sha1_abbrev = NULL; const char *action_str = opts->action == REPLAY_REVERT ? "revert" : "pick"; const char *subject; int subject_len; for (cur = todo_list; cur; cur = cur->next) { const char *commit_buffer = get_commit_buffer(cur->item, NULL); sha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV); subject_len = find_commit_subject(commit_buffer, &subject); strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev, subject_len, subject); unuse_commit_buffer(cur->item, commit_buffer); } return 0; }
static void make_cover_letter(struct rev_info *rev, int use_stdout, struct commit *origin, int nr, struct commit **list, const char *branch_name, int quiet) { const char *committer; const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n"; const char *msg; struct shortlog log; struct strbuf sb = STRBUF_INIT; int i; const char *encoding = "UTF-8"; struct diff_options opts; int need_8bit_cte = 0; struct pretty_print_context pp = {0}; struct commit *head = list[0]; if (rev->commit_format != CMIT_FMT_EMAIL) die(_("Cover letter needs email format")); committer = git_committer_info(0); if (!use_stdout && reopen_stdout(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet)) return; log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); for (i = 0; !need_8bit_cte && i < nr; i++) { const char *buf = get_commit_buffer(list[i], NULL); if (has_non_ascii(buf)) need_8bit_cte = 1; unuse_commit_buffer(list[i], buf); } if (!branch_name) branch_name = find_branch_name(rev); msg = body; pp.fmt = CMIT_FMT_EMAIL; pp.date_mode = DATE_RFC2822; pp_user_info(&pp, NULL, &sb, committer, encoding); pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte); pp_remainder(&pp, &msg, &sb, 0); add_branch_description(&sb, branch_name); printf("%s\n", sb.buf); strbuf_release(&sb); shortlog_init(&log); log.wrap_lines = 1; log.wrap = 72; log.in1 = 2; log.in2 = 4; for (i = 0; i < nr; i++) shortlog_add_commit(&log, list[i]); shortlog_output(&log); /* * We can only do diffstat with a unique reference point */ if (!origin) return; memcpy(&opts, &rev->diffopt, sizeof(opts)); opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; diff_setup_done(&opts); diff_tree_sha1(origin->tree->object.sha1, head->tree->object.sha1, "", &opts); diffcore_std(&opts); diff_flush(&opts); printf("\n"); print_signature(); }
const char *logmsg_reencode(const struct commit *commit, char **commit_encoding, const char *output_encoding) { static const char *utf8 = "UTF-8"; const char *use_encoding; char *encoding; const char *msg = get_commit_buffer(commit, NULL); char *out; if (!output_encoding || !*output_encoding) { if (commit_encoding) *commit_encoding = get_header(commit, msg, "encoding"); return msg; } encoding = get_header(commit, msg, "encoding"); if (commit_encoding) *commit_encoding = encoding; use_encoding = encoding ? encoding : utf8; if (same_encoding(use_encoding, output_encoding)) { /* * No encoding work to be done. If we have no encoding header * at all, then there's nothing to do, and we can return the * message verbatim (whether newly allocated or not). */ if (!encoding) return msg; /* * Otherwise, we still want to munge the encoding header in the * result, which will be done by modifying the buffer. If we * are using a fresh copy, we can reuse it. But if we are using * the cached copy from get_commit_buffer, we need to duplicate it * to avoid munging the cached copy. */ if (msg == get_cached_commit_buffer(commit, NULL)) out = xstrdup(msg); else out = (char *)msg; } else { /* * There's actual encoding work to do. Do the reencoding, which * still leaves the header to be replaced in the next step. At * this point, we are done with msg. If we allocated a fresh * copy, we can free it. */ out = reencode_string(msg, output_encoding, use_encoding); if (out) unuse_commit_buffer(commit, msg); } /* * This replacement actually consumes the buffer we hand it, so we do * not have to worry about freeing the old "out" here. */ if (out) out = replace_encoding_header(out, output_encoding); if (!commit_encoding) free(encoding); /* * If the re-encoding failed, out might be NULL here; in that * case we just return the commit message verbatim. */ return out ? out : msg; }
static void handle_commit(struct commit *commit, struct rev_info *rev) { int saved_output_format = rev->diffopt.output_format; const char *commit_buffer; const char *author, *author_end, *committer, *committer_end; const char *encoding, *message; char *reencoded = NULL; struct commit_list *p; const char *refname; int i; rev->diffopt.output_format = DIFF_FORMAT_CALLBACK; parse_commit_or_die(commit); commit_buffer = get_commit_buffer(commit, NULL); author = strstr(commit_buffer, "\nauthor "); if (!author) die ("Could not find author in commit %s", sha1_to_hex(commit->object.sha1)); author++; author_end = strchrnul(author, '\n'); committer = strstr(author_end, "\ncommitter "); if (!committer) die ("Could not find committer in commit %s", sha1_to_hex(commit->object.sha1)); committer++; committer_end = strchrnul(committer, '\n'); message = strstr(committer_end, "\n\n"); encoding = find_encoding(committer_end, message); if (message) message += 2; if (commit->parents && get_object_mark(&commit->parents->item->object) != 0 && !full_tree) { parse_commit_or_die(commit->parents->item); diff_tree_sha1(commit->parents->item->tree->object.sha1, commit->tree->object.sha1, "", &rev->diffopt); } else diff_root_tree_sha1(commit->tree->object.sha1, "", &rev->diffopt); /* Export the referenced blobs, and remember the marks. */ for (i = 0; i < diff_queued_diff.nr; i++) if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode)) export_blob(diff_queued_diff.queue[i]->two->sha1); refname = commit->util; if (anonymize) { refname = anonymize_refname(refname); anonymize_ident_line(&committer, &committer_end); anonymize_ident_line(&author, &author_end); } mark_next_object(&commit->object); if (anonymize) reencoded = anonymize_commit_message(message); else if (!is_encoding_utf8(encoding)) reencoded = reencode_string(message, "UTF-8", encoding); if (!commit->parents) printf("reset %s\n", refname); printf("commit %s\nmark :%"PRIu32"\n%.*s\n%.*s\ndata %u\n%s", refname, last_idnum, (int)(author_end - author), author, (int)(committer_end - committer), committer, (unsigned)(reencoded ? strlen(reencoded) : message ? strlen(message) : 0), reencoded ? reencoded : message ? message : ""); free(reencoded); unuse_commit_buffer(commit, commit_buffer); for (i = 0, p = commit->parents; p; p = p->next) { int mark = get_object_mark(&p->item->object); if (!mark) continue; if (i == 0) printf("from :%d\n", mark); else printf("merge :%d\n", mark); i++; } if (full_tree) printf("deleteall\n"); log_tree_diff_flush(rev); rev->diffopt.output_format = saved_output_format; printf("\n"); show_progress(); }
int notes_merge_commit(struct notes_merge_options *o, struct notes_tree *partial_tree, struct commit *partial_commit, struct object_id *result_oid) { /* * Iterate through files in .git/NOTES_MERGE_WORKTREE and add all * found notes to 'partial_tree'. Write the updated notes tree to * the DB, and commit the resulting tree object while reusing the * commit message and parents from 'partial_commit'. * Finally store the new commit object OID into 'result_oid'. */ DIR *dir; struct dirent *e; struct strbuf path = STRBUF_INIT; const char *buffer = get_commit_buffer(partial_commit, NULL); const char *msg = strstr(buffer, "\n\n"); int baselen; git_path_buf(&path, NOTES_MERGE_WORKTREE); if (o->verbosity >= 3) printf("Committing notes in notes merge worktree at %s\n", path.buf); if (!msg || msg[2] == '\0') die("partial notes commit has empty message"); msg += 2; dir = opendir(path.buf); if (!dir) die_errno("could not open %s", path.buf); strbuf_addch(&path, '/'); baselen = path.len; while ((e = readdir(dir)) != NULL) { struct stat st; struct object_id obj_oid, blob_oid; if (is_dot_or_dotdot(e->d_name)) continue; if (get_oid_hex(e->d_name, &obj_oid)) { if (o->verbosity >= 3) printf("Skipping non-SHA1 entry '%s%s'\n", path.buf, e->d_name); continue; } strbuf_addstr(&path, e->d_name); /* write file as blob, and add to partial_tree */ if (stat(path.buf, &st)) die_errno("Failed to stat '%s'", path.buf); if (index_path(&blob_oid, path.buf, &st, HASH_WRITE_OBJECT)) die("Failed to write blob object from '%s'", path.buf); if (add_note(partial_tree, &obj_oid, &blob_oid, NULL)) die("Failed to add resolved note '%s' to notes tree", path.buf); if (o->verbosity >= 4) printf("Added resolved note for object %s: %s\n", oid_to_hex(&obj_oid), oid_to_hex(&blob_oid)); strbuf_setlen(&path, baselen); } create_notes_commit(partial_tree, partial_commit->parents, msg, strlen(msg), result_oid->hash); unuse_commit_buffer(partial_commit, buffer); if (o->verbosity >= 4) printf("Finalized notes merge commit: %s\n", oid_to_hex(result_oid)); strbuf_release(&path); closedir(dir); return 0; }