static int edit_branch_description(const char *branch_name) { FILE *fp; int status; struct strbuf buf = STRBUF_INIT; struct strbuf name = STRBUF_INIT; read_branch_desc(&buf, branch_name); if (!buf.len || buf.buf[buf.len-1] != '\n') strbuf_addch(&buf, '\n'); strbuf_commented_addf(&buf, "Please edit the description for the branch\n" " %s\n" "Lines starting with '%c' will be stripped.\n", branch_name, comment_line_char); fp = fopen(git_path(edit_description), "w"); if ((fwrite(buf.buf, 1, buf.len, fp) < buf.len) || fclose(fp)) { strbuf_release(&buf); return error(_("could not write branch description template: %s"), strerror(errno)); } strbuf_reset(&buf); if (launch_editor(git_path(edit_description), &buf, NULL)) { strbuf_release(&buf); return -1; } stripspace(&buf, 1); strbuf_addf(&name, "branch.%s.description", branch_name); status = git_config_set(name.buf, buf.len ? buf.buf : NULL); strbuf_release(&name); strbuf_release(&buf); return status; }
static void prepare_note_data(const unsigned char *object, struct note_data *d, const unsigned char *old_note) { if (d->use_editor || !d->given) { int fd; struct strbuf buf = STRBUF_INIT; /* write the template message before editing: */ d->edit_path = git_pathdup("NOTES_EDITMSG"); fd = open(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) die_errno(_("could not create file '%s'"), d->edit_path); if (d->given) write_or_die(fd, d->buf.buf, d->buf.len); else if (old_note) copy_obj_to_fd(fd, old_note); strbuf_addch(&buf, '\n'); strbuf_add_commented_lines(&buf, note_template, strlen(note_template)); strbuf_addch(&buf, '\n'); write_or_die(fd, buf.buf, buf.len); write_commented_object(fd, object); close(fd); strbuf_release(&buf); strbuf_reset(&d->buf); if (launch_editor(d->edit_path, &d->buf, NULL)) { die(_("Please supply the note contents using either -m or -F option")); } stripspace(&d->buf, 1); } }
static int edit_branch_description(const char *branch_name) { struct strbuf buf = STRBUF_INIT; struct strbuf name = STRBUF_INIT; read_branch_desc(&buf, branch_name); if (!buf.len || buf.buf[buf.len-1] != '\n') strbuf_addch(&buf, '\n'); strbuf_commented_addf(&buf, _("Please edit the description for the branch\n" " %s\n" "Lines starting with '%c' will be stripped.\n"), branch_name, comment_line_char); write_file_buf(git_path(edit_description), buf.buf, buf.len); strbuf_reset(&buf); if (launch_editor(git_path(edit_description), &buf, NULL)) { strbuf_release(&buf); return -1; } strbuf_stripspace(&buf, 1); strbuf_addf(&name, "branch.%s.description", branch_name); git_config_set(name.buf, buf.len ? buf.buf : NULL); strbuf_release(&name); strbuf_release(&buf); return 0; }
static gboolean key_press_cb (GtkWidget *widget, GdkEventKey *event, EMsgComposer *composer) { GSettings *settings; gboolean immediately; /* we don't want to start the editor on any modifier keys */ switch (event->keyval) { case GDK_KEY_Alt_L: case GDK_KEY_Alt_R: case GDK_KEY_Super_L: case GDK_KEY_Super_R: case GDK_KEY_Control_L: case GDK_KEY_Control_R: return FALSE; default: break; } settings = g_settings_new ("org.gnome.evolution.plugin.external-editor"); immediately = g_settings_get_boolean (settings, "launch-on-key-press"); g_object_unref (settings); if (!immediately) return FALSE; launch_editor (NULL, composer); return TRUE; }
static int edit_patch(int argc, const char **argv, const char *prefix) { char *file = git_pathdup("ADD_EDIT.patch"); const char *apply_argv[] = { "apply", "--recount", "--cached", NULL, NULL }; struct child_process child = CHILD_PROCESS_INIT; struct rev_info rev; int out; struct stat st; apply_argv[3] = file; git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ if (read_cache() < 0) die(_("Could not read the index")); repo_init_revisions(the_repository, &rev, prefix); rev.diffopt.context = 7; argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; rev.diffopt.use_color = 0; rev.diffopt.flags.ignore_dirty_submodules = 1; out = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (out < 0) die(_("Could not open '%s' for writing."), file); rev.diffopt.file = xfdopen(out, "w"); rev.diffopt.close_file = 1; if (run_diff_files(&rev, 0)) die(_("Could not write patch")); if (launch_editor(file, NULL, NULL)) die(_("editing patch failed")); if (stat(file, &st)) die_errno(_("Could not stat '%s'"), file); if (!st.st_size) die(_("Empty patch. Aborted.")); child.git_cmd = 1; child.argv = apply_argv; if (run_command(&child)) die(_("Could not apply '%s'"), file); unlink(file); free(file); return 0; }
static int edit_patch(int argc, const char **argv, const char *prefix) { char *file = git_pathdup("ADD_EDIT.patch"); const char *apply_argv[] = { "apply", "--recount", "--cached", NULL, NULL }; struct child_process child; struct rev_info rev; int out; struct stat st; apply_argv[3] = file; git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ if (read_cache() < 0) die(_("Could not read the index")); init_revisions(&rev, prefix); rev.diffopt.context = 7; argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; rev.diffopt.use_color = 0; DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0666); if (out < 0) die(_("Could not open '%s' for writing."), file); rev.diffopt.file = xfdopen(out, "w"); rev.diffopt.close_file = 1; if (run_diff_files(&rev, 0)) die(_("Could not write patch")); launch_editor(file, NULL, NULL); if (stat(file, &st)) die_errno(_("Could not stat '%s'"), file); if (!st.st_size) die(_("Empty patch. Aborted.")); memset(&child, 0, sizeof(child)); child.git_cmd = 1; child.argv = apply_argv; if (run_command(&child)) die(_("Could not apply '%s'"), file); unlink(file); free(file); return 0; }
static void prepare_to_commit(void) { struct strbuf msg = STRBUF_INIT; strbuf_addbuf(&msg, &merge_msg); strbuf_addch(&msg, '\n'); write_merge_msg(&msg); run_hook(get_index_file(), "prepare-commit-msg", git_path("MERGE_MSG"), "merge", NULL, NULL); if (option_edit) { if (launch_editor(git_path("MERGE_MSG"), NULL, NULL)) abort_commit(NULL); } read_merge_msg(&msg); stripspace(&msg, option_edit); if (!msg.len) abort_commit(_("Empty commit message.")); strbuf_release(&merge_msg); strbuf_addbuf(&merge_msg, &msg); strbuf_release(&msg); }
static int edit_and_replace(const char *object_ref, int force, int raw) { char *tmpfile; enum object_type type; struct object_id old_oid, new_oid, prev; struct strbuf ref = STRBUF_INIT; if (get_oid(object_ref, &old_oid) < 0) return error("Not a valid object name: '%s'", object_ref); type = oid_object_info(the_repository, &old_oid, NULL); if (type < 0) return error("unable to get object type for %s", oid_to_hex(&old_oid)); if (check_ref_valid(&old_oid, &prev, &ref, force)) { strbuf_release(&ref); return -1; } strbuf_release(&ref); tmpfile = git_pathdup("REPLACE_EDITOBJ"); if (export_object(&old_oid, type, raw, tmpfile)) { free(tmpfile); return -1; } if (launch_editor(tmpfile, NULL, NULL) < 0) { free(tmpfile); return error("editing object file failed"); } if (import_object(&new_oid, type, raw, tmpfile)) { free(tmpfile); return -1; } free(tmpfile); if (!oidcmp(&old_oid, &new_oid)) return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid)); return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force); }
static void prepare_to_commit(struct commit_list *remoteheads) { struct strbuf msg = STRBUF_INIT; strbuf_addbuf(&msg, &merge_msg); strbuf_addch(&msg, '\n'); if (0 < option_edit) strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char); write_file_buf(git_path_merge_msg(), msg.buf, msg.len); if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg", git_path_merge_msg(), "merge", NULL)) abort_commit(remoteheads, NULL); if (0 < option_edit) { if (launch_editor(git_path_merge_msg(), NULL, NULL)) abort_commit(remoteheads, NULL); } read_merge_msg(&msg); strbuf_stripspace(&msg, 0 < option_edit); if (!msg.len) abort_commit(remoteheads, _("Empty commit message.")); strbuf_release(&merge_msg); strbuf_addbuf(&merge_msg, &msg); strbuf_release(&msg); }
static void prepare_to_commit(struct commit_list *remoteheads) { struct strbuf msg = STRBUF_INIT; const char *comment = _(merge_editor_comment); strbuf_addbuf(&msg, &merge_msg); strbuf_addch(&msg, '\n'); if (0 < option_edit) strbuf_add_lines(&msg, "# ", comment, strlen(comment)); write_merge_msg(&msg); if (run_hook(get_index_file(), "prepare-commit-msg", git_path("MERGE_MSG"), "merge", NULL, NULL)) abort_commit(remoteheads, NULL); if (0 < option_edit) { if (launch_editor(git_path("MERGE_MSG"), NULL, NULL)) abort_commit(remoteheads, NULL); } read_merge_msg(&msg); stripspace(&msg, 0 < option_edit); if (!msg.len) abort_commit(remoteheads, _("Empty commit message.")); strbuf_release(&merge_msg); strbuf_addbuf(&merge_msg, &msg); strbuf_release(&msg); }
static void create_note(const unsigned char *object, struct msg_arg *msg, int append_only, const unsigned char *prev, unsigned char *result) { char *path = NULL; if (msg->use_editor || !msg->given) { int fd; /* write the template message before editing: */ path = git_pathdup("NOTES_EDITMSG"); fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) die_errno("could not create file '%s'", path); if (msg->given) write_or_die(fd, msg->buf.buf, msg->buf.len); else if (prev && !append_only) write_note_data(fd, prev); write_or_die(fd, note_template, strlen(note_template)); write_commented_object(fd, object); close(fd); strbuf_reset(&(msg->buf)); if (launch_editor(path, &(msg->buf), NULL)) { die("Please supply the note contents using either -m" \ " or -F option"); } stripspace(&(msg->buf), 1); } if (prev && append_only) { /* Append buf to previous note contents */ unsigned long size; enum object_type type; char *prev_buf = read_sha1_file(prev, &type, &size); strbuf_grow(&(msg->buf), size + 1); if (msg->buf.len && prev_buf && size) strbuf_insert(&(msg->buf), 0, "\n", 1); if (prev_buf && size) strbuf_insert(&(msg->buf), 0, prev_buf, size); free(prev_buf); } if (!msg->buf.len) { fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object)); hashclr(result); } else { if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) { error("unable to write note object"); if (path) error("The note contents has been left in %s", path); exit(128); } } if (path) { unlink_or_warn(path); free(path); } }
int cmd_config(int argc, const char **argv, const char *prefix) { int nongit = !startup_info->have_repository; char *value; given_config_file = getenv(CONFIG_ENVIRONMENT); argc = parse_options(argc, argv, prefix, builtin_config_options, builtin_config_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (use_global_config + use_system_config + use_local_config + !!given_config_file > 1) { error("only one config file at a time."); usage_with_options(builtin_config_usage, builtin_config_options); } if (use_global_config) { char *user_config = NULL; char *xdg_config = NULL; home_config_paths(&user_config, &xdg_config, "config"); if (access(user_config, R_OK) && !access(xdg_config, R_OK)) given_config_file = xdg_config; else if (user_config) given_config_file = user_config; else die("$HOME not set"); } else if (use_system_config) given_config_file = git_etc_gitconfig(); else if (use_local_config) given_config_file = git_pathdup("config"); else if (given_config_file) { if (!is_absolute_path(given_config_file) && prefix) given_config_file = xstrdup(prefix_filename(prefix, strlen(prefix), given_config_file)); } if (respect_includes == -1) respect_includes = !given_config_file; if (end_null) { term = '\0'; delim = '\n'; key_delim = '\n'; } if (HAS_MULTI_BITS(types)) { error("only one type at a time."); usage_with_options(builtin_config_usage, builtin_config_options); } if (get_color_slot) actions |= ACTION_GET_COLOR; if (get_colorbool_slot) actions |= ACTION_GET_COLORBOOL; if ((get_color_slot || get_colorbool_slot) && types) { error("--get-color and variable type are incoherent"); usage_with_options(builtin_config_usage, builtin_config_options); } if (HAS_MULTI_BITS(actions)) { error("only one action at a time."); usage_with_options(builtin_config_usage, builtin_config_options); } if (actions == 0) switch (argc) { case 1: actions = ACTION_GET; break; case 2: actions = ACTION_SET; break; case 3: actions = ACTION_SET_ALL; break; default: usage_with_options(builtin_config_usage, builtin_config_options); } if (actions == ACTION_LIST) { check_argc(argc, 0, 0); if (git_config_with_options(show_all_config, NULL, given_config_file, respect_includes) < 0) { if (given_config_file) die_errno("unable to read config file '%s'", given_config_file); else die("error processing config file(s)"); } } else if (actions == ACTION_EDIT) { check_argc(argc, 0, 0); if (!given_config_file && nongit) die("not in a git directory"); git_config(git_default_config, NULL); launch_editor(given_config_file ? given_config_file : git_path("config"), NULL, NULL); } else if (actions == ACTION_SET) { int ret; check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); ret = git_config_set_in_file(given_config_file, argv[0], value); if (ret == CONFIG_NOTHING_SET) error("cannot overwrite multiple values with a single value\n" " Use a regexp, --add or --replace-all to change %s.", argv[0]); return ret; } else if (actions == ACTION_SET_ALL) { check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar_in_file(given_config_file, argv[0], value, argv[2], 0); } else if (actions == ACTION_ADD) { check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar_in_file(given_config_file, argv[0], value, "^$", 0); } else if (actions == ACTION_REPLACE_ALL) { check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); return git_config_set_multivar_in_file(given_config_file, argv[0], value, argv[2], 1); } else if (actions == ACTION_GET) { check_argc(argc, 1, 2); return get_value(argv[0], argv[1]); } else if (actions == ACTION_GET_ALL) { do_all = 1; check_argc(argc, 1, 2); return get_value(argv[0], argv[1]); } else if (actions == ACTION_GET_REGEXP) { show_keys = 1; use_key_regexp = 1; do_all = 1; check_argc(argc, 1, 2); return get_value(argv[0], argv[1]); } else if (actions == ACTION_UNSET) { check_argc(argc, 1, 2); if (argc == 2) return git_config_set_multivar_in_file(given_config_file, argv[0], NULL, argv[1], 0); else return git_config_set_in_file(given_config_file, argv[0], NULL); } else if (actions == ACTION_UNSET_ALL) { check_argc(argc, 1, 2); return git_config_set_multivar_in_file(given_config_file, argv[0], NULL, argv[1], 1); } else if (actions == ACTION_RENAME_SECTION) { int ret; check_argc(argc, 2, 2); ret = git_config_rename_section_in_file(given_config_file, argv[0], argv[1]); if (ret < 0) return ret; if (ret == 0) die("No such section!"); } else if (actions == ACTION_REMOVE_SECTION) { int ret; check_argc(argc, 1, 1); ret = git_config_rename_section_in_file(given_config_file, argv[0], NULL); if (ret < 0) return ret; if (ret == 0) die("No such section!"); } else if (actions == ACTION_GET_COLOR) { get_color(argv[0]); } else if (actions == ACTION_GET_COLORBOOL) { if (argc == 1) color_stdout_is_tty = git_config_bool("command line", argv[0]); return get_colorbool(argc != 0); } return 0; }
int run_commit(int argc, char const* const* argv) { int result; char tmp_file_path[PATH_MAX]; struct strbuf buffer; struct string_list files; struct strbuf message; int fd; FILE* tmp_file; printf("commit!\n"); strcpy(tmp_file_path, "/tmp/commit.XXXXXX.fut"); fd = mkstemps(tmp_file_path, 4); if (fd == -1) { fprintf(stderr, "Error opening temp file: %s.\n", tmp_file_path); return 1; } tmp_file = fdopen(fd, "w"); fprintf(tmp_file, "# Remove any files you don't want to commit, and enter a\n" "# commit message. To cancel, leave an empty commit message.\n" "\n"); fprintf(tmp_file, "Files:\n"); write_file_status(tmp_file); fprintf(tmp_file, "\n"); fprintf(tmp_file, "Commit Message:\n\n"); fclose(tmp_file); result = launch_editor(tmp_file_path, NULL, NULL); printf("editor returned %d\n", result); if (result != 0) { fprintf(stderr, "result=%d\n", result); return 1; } strbuf_init(&buffer, 0); strbuf_init(&message, 0); memset(&files, 0, sizeof(struct string_list)); files.strdup_strings = 1; if (strbuf_read_file(&buffer, tmp_file_path, 0) < 0) { result = 1; fprintf(stderr, "Error reading temp file. %s\n", strerror(errno)); goto done; } printf("They wrote --[%s]--\n", buffer.buf); result = parse_commit(&buffer, &files, &message); if (result != 0) { fprintf(stderr, "Error parsing commit message.\n"); result = 1; goto done; } if (message.len == 0 || files.nr == 0) { fprintf(stderr, "Commit aborted.\n"); result = 1; goto done; } printf("file count %d\n", files.nr); print_string_list("files--", &files); printf("\nMessage --[[%s]]--\n", message.buf); done: strbuf_release(&buffer); strbuf_release(&message); string_list_clear(&files, 0); unlink(tmp_file_path); return result; }
static int prepare_to_commit(const char *index_file, const char *prefix, struct wt_status *s) { struct stat statbuf; int commitable, saved_color_setting; struct strbuf sb = STRBUF_INIT; char *buffer; FILE *fp; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die("could not lookup commit %s", squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); if (strbuf_read(&sb, 0, 0) < 0) die_errno("could not read log from standard input"); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno("could not read log file '%s'", logfile); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); if (!buffer || buffer[2] == '\0') die("commit has empty message"); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die("could not lookup commit %s", fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die_errno("could not read MERGE_MSG"); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die_errno("could not read SQUASH_MSG"); hook_arg1 = "squash"; } else if (template_file && !stat(template_file, &statbuf)) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno("could not read '%s'", template_file); hook_arg1 = "template"; } /* * This final case does not modify the template message, * it just sets the argument to the prepare-commit-msg hook. */ else if (in_merge) hook_arg1 = "merge"; if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) die_errno("could not open '%s'", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); if (signoff) { struct strbuf sob = STRBUF_INIT; int i; strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) ; /* do nothing */ if (prefixcmp(sb.buf + i, sob.buf)) { if (!i || !ends_rfc2822_footer(&sb)) strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); } strbuf_release(&sob); } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) die_errno("could not write commit template"); strbuf_release(&sb); determine_author_info(); /* This checks if committer ident is explicitly given */ git_committer_info(0); if (use_editor && include_status) { char *author_ident; const char *committer_ident; if (in_merge) fprintf(fp, "#\n" "# It looks like you may be committing a MERGE.\n" "# If this is not correct, please remove the file\n" "# %s\n" "# and try again.\n" "#\n", git_path("MERGE_HEAD")); fprintf(fp, "\n" "# Please enter the commit message for your changes."); if (cleanup_mode == CLEANUP_ALL) fprintf(fp, " Lines starting\n" "# with '#' will be ignored, and an empty" " message aborts the commit.\n"); else /* CLEANUP_SPACE, that is. */ fprintf(fp, " Lines starting\n" "# with '#' will be kept; you may remove them" " yourself if you want to.\n" "# An empty message aborts the commit.\n"); if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); author_ident = xstrdup(fmt_name(author_name, author_email)); committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL")); if (strcmp(author_ident, committer_ident)) fprintf(fp, "%s" "# Author: %s\n", ident_shown++ ? "" : "#\n", author_ident); free(author_ident); if (!user_ident_sufficiently_given()) fprintf(fp, "%s" "# Committer: %s\n", ident_shown++ ? "" : "#\n", committer_ident); if (ident_shown) fprintf(fp, "#\n"); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die("Cannot read index"); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } fclose(fp); if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(empty_amend_advice, stderr); return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (!active_cache_tree) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { error("Error building trees"); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { NULL }; env[0] = index; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); if (launch_editor(git_path(commit_editmsg), NULL, env)) { fprintf(stderr, "Please supply the message using either -m or -F option.\n"); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
static int prepare_to_commit(const char *index_file, const char *prefix) { struct stat statbuf; int commitable, saved_color_setting; struct strbuf sb; char *buffer; FILE *fp; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; strbuf_init(&sb, 0); if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); if (strbuf_read(&sb, 0, 0) < 0) die("could not read log from standard input"); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die("could not read log file '%s': %s", logfile, strerror(errno)); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); if (!buffer || buffer[2] == '\0') die("commit has empty message"); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die("could not read MERGE_MSG: %s", strerror(errno)); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die("could not read SQUASH_MSG: %s", strerror(errno)); hook_arg1 = "squash"; } else if (template_file && !stat(template_file, &statbuf)) { if (strbuf_read_file(&sb, template_file, 0) < 0) die("could not read %s: %s", template_file, strerror(errno)); hook_arg1 = "template"; } /* * This final case does not modify the template message, * it just sets the argument to the prepare-commit-msg hook. */ else if (in_merge) hook_arg1 = "merge"; fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) die("could not open %s", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); if (signoff) { struct strbuf sob; int i; strbuf_init(&sob, 0); strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) ; /* do nothing */ if (prefixcmp(sb.buf + i, sob.buf)) { if (prefixcmp(sb.buf + i, sign_off_header)) strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); } strbuf_release(&sob); } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) die("could not write commit template: %s", strerror(errno)); strbuf_release(&sb); determine_author_info(); /* This checks if committer ident is explicitly given */ git_committer_info(0); if (use_editor) { char *author_ident; const char *committer_ident; if (in_merge) fprintf(fp, "#\n" "# It looks like you may be committing a MERGE.\n" "# If this is not correct, please remove the file\n" "# %s\n" "# and try again.\n" "#\n", git_path("MERGE_HEAD")); fprintf(fp, "\n" "# Please enter the commit message for your changes.\n" "# (Comment lines starting with '#' will "); if (cleanup_mode == CLEANUP_ALL) fprintf(fp, "not be included)\n"); else /* CLEANUP_SPACE, that is. */ fprintf(fp, "be kept.\n" "# You can remove them yourself if you want to)\n"); if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); author_ident = xstrdup(fmt_name(author_name, author_email)); committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL")); if (strcmp(author_ident, committer_ident)) fprintf(fp, "%s" "# Author: %s\n", ident_shown++ ? "" : "#\n", author_ident); free(author_ident); if (!user_ident_explicitly_given) fprintf(fp, "%s" "# Committer: %s\n", ident_shown++ ? "" : "#\n", committer_ident); if (ident_shown) fprintf(fp, "#\n"); saved_color_setting = wt_status_use_color; wt_status_use_color = 0; commitable = run_status(fp, index_file, prefix, 1); wt_status_use_color = saved_color_setting; } else { struct rev_info rev; unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die("Cannot read index"); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else { init_revisions(&rev, ""); rev.abbrev = 0; setup_revisions(0, NULL, &rev, parent); DIFF_OPT_SET(&rev.diffopt, QUIET); DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS); run_diff_index(&rev, 1 /* cached */); commitable = !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); } } fclose(fp); if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0); unlink(commit_editmsg); return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (!active_cache_tree) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { error("Error building trees"); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { index, NULL }; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); launch_editor(git_path(commit_editmsg), NULL, env); } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
static int prepare_to_commit(const char *index_file, const char *prefix, struct commit *current_head, struct wt_status *s, struct strbuf *author_ident) { struct stat statbuf; struct strbuf committer_ident = STRBUF_INIT; int commitable; struct strbuf sb = STRBUF_INIT; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int clean_message_contents = (cleanup_mode != CLEANUP_NONE); int old_display_comment_prefix; /* This checks and barfs if author is badly specified */ determine_author_info(author_ident); if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die(_("could not lookup commit %s"), squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, _("(reading log message from standard input)\n")); if (strbuf_read(&sb, 0, 0) < 0) die_errno(_("could not read log from standard input")); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno(_("could not read log file '%s'"), logfile); hook_arg1 = "message"; } else if (use_message) { char *buffer; buffer = strstr(use_message_buffer, "\n\n"); if (!use_editor && (!buffer || buffer[2] == '\0')) die(_("commit has empty message")); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die(_("could not lookup commit %s"), fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die_errno(_("could not read MERGE_MSG")); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else if (template_file) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno(_("could not read '%s'"), template_file); hook_arg1 = "template"; clean_message_contents = 0; } /* * The remaining cases don't modify the template message, but * just set the argument(s) to the prepare-commit-msg hook. */ else if (whence == FROM_MERGE) hook_arg1 = "merge"; else if (whence == FROM_CHERRY_PICK) { hook_arg1 = "commit"; hook_arg2 = "CHERRY_PICK_HEAD"; } if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } s->fp = fopen(git_path(commit_editmsg), "w"); if (s->fp == NULL) die_errno(_("could not open '%s'"), git_path(commit_editmsg)); /* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */ old_display_comment_prefix = s->display_comment_prefix; s->display_comment_prefix = 1; /* * Most hints are counter-productive when the commit has * already started. */ s->hints = 0; if (clean_message_contents) stripspace(&sb, 0); if (signoff) { /* * See if we have a Conflicts: block at the end. If yes, count * its size, so we can ignore it. */ int ignore_footer = 0; int i, eol, previous = 0; const char *nl; for (i = 0; i < sb.len; i++) { nl = memchr(sb.buf + i, '\n', sb.len - i); if (nl) eol = nl - sb.buf; else eol = sb.len; if (starts_with(sb.buf + previous, "\nConflicts:\n")) { ignore_footer = sb.len - previous; break; } while (i < eol) i++; previous = eol; } append_signoff(&sb, ignore_footer, 0); } if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); strbuf_release(&sb); /* This checks if committer ident is explicitly given */ strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT)); if (use_editor && include_status) { int ident_shown = 0; int saved_color_setting; char *ai_tmp, *ci_tmp; if (whence != FROM_COMMIT) status_printf_ln(s, GIT_COLOR_NORMAL, whence == FROM_MERGE ? _("\n" "It looks like you may be committing a merge.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n") : _("\n" "It looks like you may be committing a cherry-pick.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n"), git_path(whence == FROM_MERGE ? "MERGE_HEAD" : "CHERRY_PICK_HEAD")); fprintf(s->fp, "\n"); if (cleanup_mode == CLEANUP_ALL) status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\nwith '%c' will be ignored, and an empty" " message aborts the commit.\n"), comment_line_char); else /* CLEANUP_SPACE, that is. */ status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes." " Lines starting\n" "with '%c' will be kept; you may remove them" " yourself if you want to.\n" "An empty message aborts the commit.\n"), comment_line_char); if (only_include_assumed) status_printf_ln(s, GIT_COLOR_NORMAL, "%s", only_include_assumed); ai_tmp = cut_ident_timestamp_part(author_ident->buf); ci_tmp = cut_ident_timestamp_part(committer_ident.buf); if (strcmp(author_ident->buf, committer_ident.buf)) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Author: %s"), ident_shown++ ? "" : "\n", author_ident->buf); if (!committer_ident_sufficiently_given()) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Committer: %s"), ident_shown++ ? "" : "\n", committer_ident.buf); if (ident_shown) status_printf_ln(s, GIT_COLOR_NORMAL, ""); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; *ai_tmp = ' '; *ci_tmp = ' '; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die(_("Cannot read index")); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } strbuf_release(&committer_ident); fclose(s->fp); /* * Reject an attempt to record a non-merge empty commit without * explicit --allow-empty. In the cherry-pick case, it may be * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && !(amend && is_a_merge(current_head))) { s->display_comment_prefix = old_display_comment_prefix; run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); else if (whence == FROM_CHERRY_PICK) { fputs(_(empty_cherry_pick_advice), stderr); if (!sequencer_in_use) fputs(_(empty_cherry_pick_advice_single), stderr); else fputs(_(empty_cherry_pick_advice_multi), stderr); } return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (update_main_cache_tree(0)) { error(_("Error building trees")); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { NULL }; env[0] = index; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); if (launch_editor(git_path(commit_editmsg), NULL, env)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
static void create_tag(const unsigned char *object, const char *tag, struct strbuf *buf, struct create_tag_options *opt, unsigned char *prev, unsigned char *result) { enum object_type type; char header_buf[1024]; int header_len; char *path = NULL; type = sha1_object_info(object, NULL); if (type <= OBJ_NONE) die(_("bad object type.")); header_len = snprintf(header_buf, sizeof(header_buf), "object %s\n" "type %s\n" "tag %s\n" "tagger %s\n\n", sha1_to_hex(object), typename(type), tag, git_committer_info(IDENT_STRICT)); if (header_len > sizeof(header_buf) - 1) die(_("tag header too big.")); if (!opt->message_given) { int fd; /* write the template message before editing: */ path = git_pathdup("TAG_EDITMSG"); fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) die_errno(_("could not create file '%s'"), path); if (!is_null_sha1(prev)) { write_tag_body(fd, prev); } else { struct strbuf buf = STRBUF_INIT; strbuf_addch(&buf, '\n'); if (opt->cleanup_mode == CLEANUP_ALL) strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char); else strbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char); write_or_die(fd, buf.buf, buf.len); strbuf_release(&buf); } close(fd); if (launch_editor(path, buf, NULL)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } } if (opt->cleanup_mode != CLEANUP_NONE) strbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL); if (!opt->message_given && !buf->len) die(_("no tag message?")); strbuf_insert(buf, 0, header_buf, header_len); if (build_tag_object(buf, opt->sign, result) < 0) { if (path) fprintf(stderr, _("The tag message has been left in %s\n"), path); exit(128); } if (path) { unlink_or_warn(path); free(path); } }