From f5bbc3225c4b073a7ff3218164a0c820299bc9c6 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Thu, 8 Nov 2007 11:59:00 -0500 Subject: Port git commit to C. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes git commit a builtin and moves git-commit.sh to contrib/examples. This also removes the git-runstatus helper, which was mostly just a git-status.sh implementation detail. Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 614 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 614 insertions(+) create mode 100644 builtin-commit.c (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c new file mode 100644 index 0000000000..669cc6b6f1 --- /dev/null +++ b/builtin-commit.c @@ -0,0 +1,614 @@ +/* + * Builtin "git commit" + * + * Copyright (c) 2007 Kristian Høgsberg + * Based on git-commit.sh by Junio C Hamano and Linus Torvalds + */ + +#include "cache.h" +#include "cache-tree.h" +#include "builtin.h" +#include "diff.h" +#include "diffcore.h" +#include "commit.h" +#include "revision.h" +#include "wt-status.h" +#include "run-command.h" +#include "refs.h" +#include "log-tree.h" +#include "strbuf.h" +#include "utf8.h" +#include "parse-options.h" + +static const char * const builtin_commit_usage[] = { + "git-commit [options] [--] ...", + NULL +}; + +static unsigned char head_sha1[20], merge_head_sha1[20]; +static char *use_message_buffer; +static const char commit_editmsg[] = "COMMIT_EDITMSG"; +static struct lock_file lock_file; + +static char *logfile, *force_author, *message, *template_file; +static char *edit_message, *use_message; +static int all, edit_flag, also, interactive, only, amend, signoff; +static int quiet, verbose, untracked_files, no_verify; + +static int no_edit, initial_commit, in_merge; +const char *only_include_assumed; + +static struct option builtin_commit_options[] = { + OPT__QUIET(&quiet), + OPT__VERBOSE(&verbose), + OPT_GROUP("Commit message options"), + + OPT_STRING('F', "file", &logfile, "FILE", "read log from file"), + OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"), + OPT_STRING('m', "message", &message, "MESSAGE", "specify commit message"), + OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "), + OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), + OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"), + OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"), + OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"), + + OPT_GROUP("Commit contents options"), + OPT_BOOLEAN('a', "all", &all, "commit all changed files"), + OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"), + OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), + OPT_BOOLEAN('o', "only", &only, ""), + OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), + OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), + OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"), + + OPT_END() +}; + +static char *prepare_index(const char **files, const char *prefix) +{ + int fd; + struct tree *tree; + struct lock_file *next_index_lock; + + if (interactive) { + interactive_add(); + return get_index_file(); + } + + fd = hold_locked_index(&lock_file, 1); + if (read_cache() < 0) + die("index file corrupt"); + + if (all || also) { + add_files_to_cache(verbose, also ? prefix : NULL, files); + if (write_cache(fd, active_cache, active_nr) || close(fd)) + die("unable to write new_index file"); + return lock_file.filename; + } + + if (*files == NULL) { + /* Commit index as-is. */ + rollback_lock_file(&lock_file); + return get_index_file(); + } + + /* update the user index file */ + add_files_to_cache(verbose, prefix, files); + if (write_cache(fd, active_cache, active_nr) || close(fd)) + die("unable to write new_index file"); + + if (!initial_commit) { + tree = parse_tree_indirect(head_sha1); + if (!tree) + die("failed to unpack HEAD tree object"); + if (read_tree(tree, 0, NULL)) + die("failed to read HEAD tree object"); + } + + /* Use a lock file to garbage collect the temporary index file. */ + next_index_lock = xmalloc(sizeof(*next_index_lock)); + fd = hold_lock_file_for_update(next_index_lock, + git_path("next-index-%d", getpid()), 1); + add_files_to_cache(verbose, prefix, files); + if (write_cache(fd, active_cache, active_nr) || close(fd)) + die("unable to write new_index file"); + + return next_index_lock->filename; +} + +static int run_status(FILE *fp, const char *index_file) +{ + struct wt_status s; + + wt_status_prepare(&s); + + if (amend) { + s.amend = 1; + s.reference = "HEAD^1"; + } + s.verbose = verbose; + s.untracked = untracked_files; + s.index_file = index_file; + s.fp = fp; + + wt_status_print(&s); + + return s.commitable; +} + +static const char sign_off_header[] = "Signed-off-by: "; + +static int prepare_log_message(const char *index_file) +{ + struct stat statbuf; + int commitable; + struct strbuf sb; + char *buffer; + FILE *fp; + + strbuf_init(&sb, 0); + if (message) { + strbuf_add(&sb, message, strlen(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"); + } else if (logfile) { + if (strbuf_read_file(&sb, logfile, 0) < 0) + die("could not read log file '%s': %s", + logfile, strerror(errno)); + } 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)); + } 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)); + } 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)); + } 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)); + } + + fp = fopen(git_path(commit_editmsg), "w"); + if (fp == NULL) + die("could not open %s\n", git_path(commit_editmsg)); + + stripspace(&sb, 0); + if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) + die("could not write commit template: %s\n", + strerror(errno)); + + if (signoff) { + const char *info, *bol; + + info = git_committer_info(1); + strbuf_addch(&sb, '\0'); + bol = strrchr(sb.buf + sb.len - 1, '\n'); + if (!bol || prefixcmp(bol, sign_off_header)) + fprintf(fp, "\n"); + fprintf(fp, "%s%s\n", sign_off_header, git_committer_info(1)); + } + + strbuf_release(&sb); + + if (in_merge && !no_edit) + 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 not be included)\n"); + if (only_include_assumed) + fprintf(fp, "# %s\n", only_include_assumed); + + commitable = run_status(fp, index_file); + + fclose(fp); + + return commitable; +} + +/* + * Find out if the message starting at position 'start' in the strbuf + * contains only whitespace and Signed-off-by lines. + */ +static int message_is_empty(struct strbuf *sb, int start) +{ + struct strbuf tmpl; + const char *nl; + int eol, i; + + /* See if the template is just a prefix of the message. */ + strbuf_init(&tmpl, 0); + if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) { + stripspace(&tmpl, 1); + if (start + tmpl.len <= sb->len && + memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0) + start += tmpl.len; + } + strbuf_release(&tmpl); + + /* Check if the rest is just whitespace and Signed-of-by's. */ + for (i = start; i < sb->len; i++) { + nl = memchr(sb->buf + i, '\n', sb->len - i); + if (nl) + eol = nl - sb->buf; + else + eol = sb->len; + + if (strlen(sign_off_header) <= eol - i && + !prefixcmp(sb->buf + i, sign_off_header)) { + i = eol; + continue; + } + while (i < eol) + if (!isspace(sb->buf[i++])) + return 0; + } + + return 1; +} + +static void determine_author_info(struct strbuf *sb) +{ + char *name, *email, *date; + + name = getenv("GIT_AUTHOR_NAME"); + email = getenv("GIT_AUTHOR_EMAIL"); + date = getenv("GIT_AUTHOR_DATE"); + + if (use_message) { + const char *a, *lb, *rb, *eol; + + a = strstr(use_message_buffer, "\nauthor "); + if (!a) + die("invalid commit: %s\n", use_message); + + lb = strstr(a + 8, " <"); + rb = strstr(a + 8, "> "); + eol = strchr(a + 8, '\n'); + if (!lb || !rb || !eol) + die("invalid commit: %s\n", use_message); + + name = xstrndup(a + 8, lb - (a + 8)); + email = xstrndup(lb + 2, rb - (lb + 2)); + date = xstrndup(rb + 2, eol - (rb + 2)); + } + + if (force_author) { + const char *lb = strstr(force_author, " <"); + const char *rb = strchr(force_author, '>'); + + if (!lb || !rb) + die("malformed --author parameter\n"); + name = xstrndup(force_author, lb - force_author); + email = xstrndup(lb + 2, rb - (lb + 2)); + } + + strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, 1)); +} + +static int parse_and_validate_options(int argc, const char *argv[]) +{ + int f = 0; + + argc = parse_options(argc, argv, builtin_commit_options, + builtin_commit_usage, 0); + + if (logfile || message || use_message) + no_edit = 1; + if (edit_flag) + no_edit = 0; + + if (get_sha1("HEAD", head_sha1)) + initial_commit = 1; + + if (!get_sha1("MERGE_HEAD", merge_head_sha1)) + in_merge = 1; + + /* Sanity check options */ + if (amend && initial_commit) + die("You have nothing to amend."); + if (amend && in_merge) + die("You are in the middle of a merger -- cannot amend."); + + if (use_message) + f++; + if (edit_message) + f++; + if (logfile) + f++; + if (f > 1) + die("Only one of -c/-C/-F can be used."); + if (message && f > 0) + die("Option -m cannot be combined with -c/-C/-F."); + if (edit_message) + use_message = edit_message; + if (amend) + use_message = "HEAD"; + if (use_message) { + unsigned char sha1[20]; + static char utf8[] = "UTF-8"; + const char *out_enc; + char *enc, *end; + struct commit *commit; + + if (get_sha1(use_message, sha1)) + die("could not lookup commit %s", use_message); + commit = lookup_commit(sha1); + if (!commit || parse_commit(commit)) + die("could not parse commit %s", use_message); + + enc = strstr(commit->buffer, "\nencoding"); + if (enc) { + end = strchr(enc + 10, '\n'); + enc = xstrndup(enc + 10, end - (enc + 10)); + } else { + enc = utf8; + } + out_enc = git_commit_encoding ? git_commit_encoding : utf8; + + if (strcmp(out_enc, enc)) + use_message_buffer = + reencode_string(commit->buffer, out_enc, enc); + + /* + * If we failed to reencode the buffer, just copy it + * byte for byte so the user can try to fix it up. + * This also handles the case where input and output + * encodings are identical. + */ + if (use_message_buffer == NULL) + use_message_buffer = xstrdup(commit->buffer); + if (enc != utf8) + free(enc); + } + + if (!!also + !!only + !!all + !!interactive > 1) + die("Only one of --include/--only/--all/--interactive can be used."); + if (argc == 0 && (also || (only && !amend))) + die("No paths with --include/--only does not make sense."); + if (argc == 0 && only && amend) + only_include_assumed = "Clever... amending the last one with dirty index."; + if (argc > 0 && !also && !only) { + only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths..."; + also = 0; + } + + if (all && argc > 0) + die("Paths with -a does not make sense."); + else if (interactive && argc > 0) + die("Paths with --interactive does not make sense."); + + return argc; +} + +int cmd_status(int argc, const char **argv, const char *prefix) +{ + const char *index_file; + int commitable; + + git_config(git_status_config); + + argc = parse_and_validate_options(argc, argv); + + index_file = prepare_index(argv, prefix); + + commitable = run_status(stdout, index_file); + + rollback_lock_file(&lock_file); + + return commitable ? 0 : 1; +} + +static int run_hook(const char *index_file, const char *name, const char *arg) +{ + struct child_process hook; + const char *argv[3], *env[2]; + char index[PATH_MAX]; + + argv[0] = git_path("hooks/%s", name); + argv[1] = arg; + argv[2] = NULL; + snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); + env[0] = index; + env[1] = NULL; + + if (access(argv[0], X_OK) < 0) + return 0; + + memset(&hook, 0, sizeof(hook)); + hook.argv = argv; + hook.no_stdin = 1; + hook.stdout_to_stderr = 1; + hook.env = env; + + return run_command(&hook); +} + +static void print_summary(const char *prefix, const unsigned char *sha1) +{ + struct rev_info rev; + struct commit *commit; + + commit = lookup_commit(sha1); + if (!commit) + die("couldn't look up newly created commit\n"); + if (!commit || parse_commit(commit)) + die("could not parse newly created commit"); + + init_revisions(&rev, prefix); + setup_revisions(0, NULL, &rev, NULL); + + rev.abbrev = 0; + rev.diff = 1; + rev.diffopt.output_format = + DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY; + + rev.verbose_header = 1; + rev.show_root_diff = 1; + rev.commit_format = get_commit_format("format:%h: %s"); + rev.always_show_header = 1; + + printf("Created %scommit ", initial_commit ? "initial " : ""); + + log_tree_commit(&rev, commit); +} + +int git_commit_config(const char *k, const char *v) +{ + if (!strcmp(k, "commit.template")) { + template_file = xstrdup(v); + return 0; + } + + return git_status_config(k, v); +} + +static const char commit_utf8_warn[] = +"Warning: commit message does not conform to UTF-8.\n" +"You may want to amend it after fixing the message, or set the config\n" +"variable i18n.commitencoding to the encoding your project uses.\n"; + +int cmd_commit(int argc, const char **argv, const char *prefix) +{ + int header_len, parent_count = 0; + struct strbuf sb; + const char *index_file, *reflog_msg; + char *nl, *header_line; + unsigned char commit_sha1[20]; + struct ref_lock *ref_lock; + + git_config(git_commit_config); + + argc = parse_and_validate_options(argc, argv); + + index_file = prepare_index(argv, prefix); + + if (!no_verify && run_hook(index_file, "pre-commit", NULL)) + exit(1); + + if (!prepare_log_message(index_file) && !in_merge) { + run_status(stdout, index_file); + unlink(commit_editmsg); + return 1; + } + + strbuf_init(&sb, 0); + + /* Start building up the commit header */ + read_cache_from(index_file); + active_cache_tree = cache_tree(); + if (cache_tree_update(active_cache_tree, + active_cache, active_nr, 0, 0) < 0) + die("Error building trees"); + strbuf_addf(&sb, "tree %s\n", + sha1_to_hex(active_cache_tree->sha1)); + + /* Determine parents */ + if (initial_commit) { + reflog_msg = "commit (initial)"; + parent_count = 0; + } else if (amend) { + struct commit_list *c; + struct commit *commit; + + reflog_msg = "commit (amend)"; + commit = lookup_commit(head_sha1); + if (!commit || parse_commit(commit)) + die("could not parse HEAD commit"); + + for (c = commit->parents; c; c = c->next) + strbuf_addf(&sb, "parent %s\n", + sha1_to_hex(c->item->object.sha1)); + } else if (in_merge) { + struct strbuf m; + FILE *fp; + + reflog_msg = "commit (merge)"; + strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1)); + strbuf_init(&m, 0); + fp = fopen(git_path("MERGE_HEAD"), "r"); + if (fp == NULL) + die("could not open %s for reading: %s", + git_path("MERGE_HEAD"), strerror(errno)); + while (strbuf_getline(&m, fp, '\n') != EOF) + strbuf_addf(&sb, "parent %s\n", m.buf); + fclose(fp); + strbuf_release(&m); + } else { + reflog_msg = "commit"; + strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1)); + } + + determine_author_info(&sb); + strbuf_addf(&sb, "committer %s\n", git_committer_info(1)); + if (!is_encoding_utf8(git_commit_encoding)) + strbuf_addf(&sb, "encoding %s\n", git_commit_encoding); + strbuf_addch(&sb, '\n'); + + /* Get the commit message and validate it */ + header_len = sb.len; + if (!no_edit) { + fprintf(stderr, "launching editor, log %s\n", logfile); + launch_editor(git_path(commit_editmsg), &sb); + } else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) + die("could not read commit message\n"); + if (run_hook(index_file, "commit-msg", commit_editmsg)) + exit(1); + stripspace(&sb, 1); + if (sb.len < header_len || + message_is_empty(&sb, header_len)) + die("* no commit message? aborting commit."); + strbuf_addch(&sb, '\0'); + if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf)) + fprintf(stderr, commit_utf8_warn); + + if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) + die("failed to write commit object"); + + ref_lock = lock_any_ref_for_update("HEAD", + initial_commit ? NULL : head_sha1, + 0); + + nl = strchr(sb.buf + header_len, '\n'); + header_line = xstrndup(sb.buf + header_len, + nl - (sb.buf + header_len)); + strbuf_release(&sb); + strbuf_addf(&sb, "%s: %s\n", reflog_msg, header_line); + strbuf_addch(&sb, '\0'); + free(header_line); + + if (!ref_lock) + die("cannot lock HEAD ref"); + if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) + die("cannot update HEAD ref"); + + unlink(git_path("MERGE_HEAD")); + unlink(git_path("MERGE_MSG")); + + if (lock_file.filename[0] && commit_locked_index(&lock_file)) + die("failed to write new index"); + + rerere(); + + run_hook(index_file, "post-commit", NULL); + + if (!quiet) + print_summary(prefix, commit_sha1); + + return 0; +} -- cgit v1.3 From 741707b1e2261d522a92948ff7d7b897ff00e587 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 8 Nov 2007 12:15:26 +0000 Subject: builtin-commit: fix reflog message generation Instead of strdup()ing, we can just reuse the buffer in which the commit message is stored, and which is supposed to hold the reflog message anyway. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 669cc6b6f1..c8f79a88fb 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -488,7 +488,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) int header_len, parent_count = 0; struct strbuf sb; const char *index_file, *reflog_msg; - char *nl, *header_line; + char *nl; unsigned char commit_sha1[20]; struct ref_lock *ref_lock; @@ -585,12 +585,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix) 0); nl = strchr(sb.buf + header_len, '\n'); - header_line = xstrndup(sb.buf + header_len, - nl - (sb.buf + header_len)); - strbuf_release(&sb); - strbuf_addf(&sb, "%s: %s\n", reflog_msg, header_line); - strbuf_addch(&sb, '\0'); - free(header_line); + if (nl) + strbuf_setlen(&sb, nl + 1 - sb.buf); + else + strbuf_addch(&sb, '\n'); + strbuf_remove(&sb, 0, header_len); + strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg)); + strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); if (!ref_lock) die("cannot lock HEAD ref"); -- cgit v1.3 From d37d320386369375b4e5b95b98517503125376f9 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Fri, 9 Nov 2007 11:40:27 -0500 Subject: builtin-commit: Refresh cache after adding files. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have promised our users that after running git-status or git-commit the index will be refreshed for a long time since these commands were introduced. Do refresh the index before writing it out to keep the promise. Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index c8f79a88fb..a84a729da1 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -81,6 +81,7 @@ static char *prepare_index(const char **files, const char *prefix) if (all || also) { add_files_to_cache(verbose, also ? prefix : NULL, files); + refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close(fd)) die("unable to write new_index file"); return lock_file.filename; @@ -110,6 +111,7 @@ static char *prepare_index(const char **files, const char *prefix) fd = hold_lock_file_for_update(next_index_lock, git_path("next-index-%d", getpid()), 1); add_files_to_cache(verbose, prefix, files); + refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close(fd)) die("unable to write new_index file"); -- cgit v1.3 From 367c98866c340bc9cf5cfa88c3b69f027165fc44 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 11 Nov 2007 17:35:41 +0000 Subject: git status: show relative paths when run in a subdirectory To show the relative paths, the function formerly called quote_crlf() (now called quote_path()) takes the prefix as an additional argument. While at it, the static buffers were replaced by strbufs. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 13 ++++---- builtin-runstatus.c | 1 + t/t7502-status.sh | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ wt-status.c | 69 ++++++++++++++++++++++++++-------------- wt-status.h | 1 + 5 files changed, 146 insertions(+), 29 deletions(-) create mode 100755 t/t7502-status.sh (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index a84a729da1..400ee93a93 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -118,11 +118,12 @@ static char *prepare_index(const char **files, const char *prefix) return next_index_lock->filename; } -static int run_status(FILE *fp, const char *index_file) +static int run_status(FILE *fp, const char *index_file, const char *prefix) { struct wt_status s; wt_status_prepare(&s); + s.prefix = prefix; if (amend) { s.amend = 1; @@ -140,7 +141,7 @@ static int run_status(FILE *fp, const char *index_file) static const char sign_off_header[] = "Signed-off-by: "; -static int prepare_log_message(const char *index_file) +static int prepare_log_message(const char *index_file, const char *prefix) { struct stat statbuf; int commitable; @@ -216,7 +217,7 @@ static int prepare_log_message(const char *index_file) if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); - commitable = run_status(fp, index_file); + commitable = run_status(fp, index_file, prefix); fclose(fp); @@ -409,7 +410,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) index_file = prepare_index(argv, prefix); - commitable = run_status(stdout, index_file); + commitable = run_status(stdout, index_file, prefix); rollback_lock_file(&lock_file); @@ -503,8 +504,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!no_verify && run_hook(index_file, "pre-commit", NULL)) exit(1); - if (!prepare_log_message(index_file) && !in_merge) { - run_status(stdout, index_file); + if (!prepare_log_message(index_file, prefix) && !in_merge) { + run_status(stdout, index_file, prefix); unlink(commit_editmsg); return 1; } diff --git a/builtin-runstatus.c b/builtin-runstatus.c index 2db25c88bf..8d167a9674 100644 --- a/builtin-runstatus.c +++ b/builtin-runstatus.c @@ -14,6 +14,7 @@ int cmd_runstatus(int argc, const char **argv, const char *prefix) git_config(git_status_config); wt_status_prepare(&s); + s.prefix = prefix; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "--color")) diff --git a/t/t7502-status.sh b/t/t7502-status.sh new file mode 100755 index 0000000000..269b3341a2 --- /dev/null +++ b/t/t7502-status.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# +# Copyright (c) 2007 Johannes E. Schindelin +# + +test_description='git-status' + +. ./test-lib.sh + +test_expect_success 'setup' ' + : > tracked && + : > modified && + mkdir dir1 && + : > dir1/tracked && + : > dir1/modified && + mkdir dir2 && + : > dir1/tracked && + : > dir1/modified && + git add . && + test_tick && + git commit -m initial && + : > untracked && + : > dir1/untracked && + : > dir2/untracked && + echo 1 > dir1/modified && + echo 2 > dir2/modified && + echo 3 > dir2/added && + git add dir2/added +' + +cat > expect << \EOF +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# new file: dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# dir1/untracked +# dir2/modified +# dir2/untracked +# expect +# output +# untracked +EOF + +test_expect_success 'status' ' + + git status > output && + git diff expect output + +' + +cat > expect << \EOF +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# new file: ../dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# +# modified: ../dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# untracked +# ../dir2/modified +# ../dir2/untracked +# ../expect +# ../output +# ../untracked +EOF + +test_expect_success 'status with relative paths' ' + + (cd dir1 && git status) > output && + git diff expect output + +' + +test_done diff --git a/wt-status.c b/wt-status.c index 9a6ef4a89a..d3c10b8b8d 100644 --- a/wt-status.c +++ b/wt-status.c @@ -81,33 +81,46 @@ static void wt_status_print_trailer(struct wt_status *s) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#"); } -static const char *quote_crlf(const char *in, char *buf, size_t sz) +static char *quote_path(const char *in, int len, + struct strbuf *out, const char *prefix) { - const char *scan; - char *out; - const char *ret = in; + if (len > 0) + strbuf_grow(out, len); + strbuf_setlen(out, 0); + + if (prefix) { + int off = 0; + while (prefix[off] && off < len && prefix[off] == in[off]) + if (prefix[off] == '/') { + prefix += off + 1; + in += off + 1; + len -= off + 1; + off = 0; + } else + off++; + + for (; *prefix; prefix++) + if (*prefix == '/') + strbuf_addstr(out, "../"); + } - for (scan = in, out = buf; *scan; scan++) { - int ch = *scan; - int quoted; + for (; (len < 0 && *in) || len > 0; in++, len--) { + int ch = *in; switch (ch) { case '\n': - quoted = 'n'; + strbuf_addstr(out, "\\n"); break; case '\r': - quoted = 'r'; + strbuf_addstr(out, "\\r"); break; default: - *out++ = ch; + strbuf_addch(out, ch); continue; } - *out++ = '\\'; - *out++ = quoted; - ret = buf; } - *out = '\0'; - return ret; + + return out->buf; } static void wt_status_print_filepair(struct wt_status *s, @@ -115,10 +128,12 @@ static void wt_status_print_filepair(struct wt_status *s, { const char *c = color(t); const char *one, *two; - char onebuf[PATH_MAX], twobuf[PATH_MAX]; + struct strbuf onebuf, twobuf; - one = quote_crlf(p->one->path, onebuf, sizeof(onebuf)); - two = quote_crlf(p->two->path, twobuf, sizeof(twobuf)); + strbuf_init(&onebuf, 0); + strbuf_init(&twobuf, 0); + one = quote_path(p->one->path, -1, &onebuf, s->prefix); + two = quote_path(p->two->path, -1, &twobuf, s->prefix); color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); switch (p->status) { @@ -150,6 +165,8 @@ static void wt_status_print_filepair(struct wt_status *s, die("bug: unhandled diff status %c", p->status); } fprintf(s->fp, "\n"); + strbuf_release(&onebuf); + strbuf_release(&twobuf); } static void wt_status_print_updated_cb(struct diff_queue_struct *q, @@ -204,8 +221,9 @@ static void wt_read_cache(struct wt_status *s) static void wt_status_print_initial(struct wt_status *s) { int i; - char buf[PATH_MAX]; + struct strbuf buf; + strbuf_init(&buf, 0); wt_read_cache(s); if (active_nr) { s->commitable = 1; @@ -214,11 +232,12 @@ static void wt_status_print_initial(struct wt_status *s) for (i = 0; i < active_nr; i++) { color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); color_fprintf_ln(s->fp, color(WT_STATUS_UPDATED), "new file: %s", - quote_crlf(active_cache[i]->name, - buf, sizeof(buf))); + quote_path(active_cache[i]->name, -1, + &buf, s->prefix)); } if (active_nr) wt_status_print_trailer(s); + strbuf_release(&buf); } static void wt_status_print_updated(struct wt_status *s) @@ -252,7 +271,9 @@ static void wt_status_print_untracked(struct wt_status *s) struct dir_struct dir; int i; int shown_header = 0; + struct strbuf buf; + strbuf_init(&buf, 0); memset(&dir, 0, sizeof(dir)); if (!s->untracked) { @@ -284,9 +305,11 @@ static void wt_status_print_untracked(struct wt_status *s) shown_header = 1; } color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t"); - color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%.*s", - ent->len, ent->name); + color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%s", + quote_path(ent->name, ent->len, + &buf, s->prefix)); } + strbuf_release(&buf); } static void wt_status_print_verbose(struct wt_status *s) diff --git a/wt-status.h b/wt-status.h index 77449326db..f58ebcbb23 100644 --- a/wt-status.h +++ b/wt-status.h @@ -23,6 +23,7 @@ struct wt_status { int workdir_untracked; const char *index_file; FILE *fp; + const char *prefix; }; int git_status_config(const char *var, const char *value); -- cgit v1.3 From 13208572fbe8838fd8835548d7502202d1f7b21d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 11 Nov 2007 17:35:58 +0000 Subject: builtin-commit: fix --signoff The Signed-off-by: line contained a spurious timestamp. The reason was a call to git_committer_info(1), which automatically added the timestamp. Instead, fmt_ident() was taught to interpret an empty string for the date (as opposed to NULL, which still triggers the default behavior) as "do not bother with the timestamp", and builtin-commit.c uses it. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 30 +++++++++++++++++++----------- ident.c | 10 +++++++--- t/t7500-commit.sh | 12 ++++++++++++ 3 files changed, 38 insertions(+), 14 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 400ee93a93..780eec79bd 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -183,21 +183,29 @@ static int prepare_log_message(const char *index_file, const char *prefix) die("could not open %s\n", git_path(commit_editmsg)); stripspace(&sb, 0); - if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) - die("could not write commit template: %s\n", - strerror(errno)); if (signoff) { - const char *info, *bol; - - info = git_committer_info(1); - strbuf_addch(&sb, '\0'); - bol = strrchr(sb.buf + sb.len - 1, '\n'); - if (!bol || prefixcmp(bol, sign_off_header)) - fprintf(fp, "\n"); - fprintf(fp, "%s%s\n", sign_off_header, git_committer_info(1)); + struct strbuf sob; + int i; + + strbuf_init(&sob, 0); + strbuf_addstr(&sob, sign_off_header); + strbuf_addstr(&sob, fmt_ident(getenv("GIT_COMMITTER_NAME"), + getenv("GIT_COMMITTER_EMAIL"), + "", 1)); + 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)) + strbuf_addbuf(&sb, &sob); + strbuf_release(&sob); } + if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) + die("could not write commit template: %s\n", + strerror(errno)); + strbuf_release(&sb); if (in_merge && !no_edit) diff --git a/ident.c b/ident.c index 9b2a852cb0..5be7533ffd 100644 --- a/ident.c +++ b/ident.c @@ -224,13 +224,17 @@ const char *fmt_ident(const char *name, const char *email, } strcpy(date, git_default_date); - if (date_str) - parse_date(date_str, date, sizeof(date)); + if (date_str) { + if (*date_str) + parse_date(date_str, date, sizeof(date)); + else + date[0] = '\0'; + } i = copy(buffer, sizeof(buffer), 0, name); i = add_raw(buffer, sizeof(buffer), i, " <"); i = copy(buffer, sizeof(buffer), i, email); - i = add_raw(buffer, sizeof(buffer), i, "> "); + i = add_raw(buffer, sizeof(buffer), i, date[0] ? "> " : ">"); i = copy(buffer, sizeof(buffer), i, date); if (i >= sizeof(buffer)) die("Impossibly long personal identifier"); diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh index cf389b81da..49c1922dde 100755 --- a/t/t7500-commit.sh +++ b/t/t7500-commit.sh @@ -122,7 +122,19 @@ test_expect_success 'using alternate GIT_INDEX_FILE (2)' ' ) && cmp .git/index saved-index >/dev/null +' +cat > expect << EOF +zort +Signed-off-by: C O Mitter +EOF + +test_expect_success '--signoff' ' + echo "yet another content *narf*" >> foo && + echo "zort" | + GIT_EDITOR=../t7500/add-content git commit -s -F - foo && + git cat-file commit HEAD | sed "1,/^$/d" > output && + diff expect output ' test_done -- cgit v1.3 From 2150554b0ed60356d8918b610834c04ad2eecdec Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 11 Nov 2007 17:36:27 +0000 Subject: builtin-commit --s: add a newline if the last line was not a S-o-b The rule is this: if the last line already contains the sign off by the current committer, do nothing. If it contains another sign off, just add the sign off of the current committer. If the last line does not contain a sign off, add a new line before adding the sign off. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 5 ++++- t/t7500-commit.sh | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 780eec79bd..4dfa802758 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -197,8 +197,11 @@ static int prepare_log_message(const char *index_file, const char *prefix) 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, sob.buf)) { + if (prefixcmp(sb.buf + i, sign_off_header)) + strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); + } strbuf_release(&sob); } diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh index 49c1922dde..baed6ce96b 100755 --- a/t/t7500-commit.sh +++ b/t/t7500-commit.sh @@ -126,6 +126,7 @@ test_expect_success 'using alternate GIT_INDEX_FILE (2)' ' cat > expect << EOF zort + Signed-off-by: C O Mitter EOF -- cgit v1.3 From f9568530c97757d840171c685fd623e1f68bc552 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 11 Nov 2007 17:36:39 +0000 Subject: builtin-commit: resurrect behavior for multiple -m options When more than one -m option is given, the message does not replace the previous, but is appended as a new paragraph. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 4dfa802758..ee79cf1b72 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -30,13 +30,27 @@ static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; static struct lock_file lock_file; -static char *logfile, *force_author, *message, *template_file; +static char *logfile, *force_author, *template_file; static char *edit_message, *use_message; static int all, edit_flag, also, interactive, only, amend, signoff; static int quiet, verbose, untracked_files, no_verify; static int no_edit, initial_commit, in_merge; const char *only_include_assumed; +struct strbuf message; + +static int opt_parse_m(const struct option *opt, const char *arg, int unset) +{ + struct strbuf *buf = opt->value; + if (unset) + strbuf_setlen(buf, 0); + else { + strbuf_addstr(buf, arg); + strbuf_addch(buf, '\n'); + strbuf_addch(buf, '\n'); + } + return 0; +} static struct option builtin_commit_options[] = { OPT__QUIET(&quiet), @@ -45,7 +59,7 @@ static struct option builtin_commit_options[] = { OPT_STRING('F', "file", &logfile, "FILE", "read log from file"), OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"), - OPT_STRING('m', "message", &message, "MESSAGE", "specify commit message"), + OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m), OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "), OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"), @@ -150,8 +164,8 @@ static int prepare_log_message(const char *index_file, const char *prefix) FILE *fp; strbuf_init(&sb, 0); - if (message) { - strbuf_add(&sb, message, strlen(message)); + if (message.len) { + strbuf_addbuf(&sb, &message); } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); @@ -322,7 +336,7 @@ static int parse_and_validate_options(int argc, const char *argv[]) argc = parse_options(argc, argv, builtin_commit_options, builtin_commit_usage, 0); - if (logfile || message || use_message) + if (logfile || message.len || use_message) no_edit = 1; if (edit_flag) no_edit = 0; @@ -347,7 +361,7 @@ static int parse_and_validate_options(int argc, const char *argv[]) f++; if (f > 1) die("Only one of -c/-C/-F can be used."); - if (message && f > 0) + if (message.len && f > 0) die("Option -m cannot be combined with -c/-C/-F."); if (edit_message) use_message = edit_message; -- cgit v1.3 From 129fa606365c172d07a5d98bea9345277f221363 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 11 Nov 2007 17:36:52 +0000 Subject: builtin-commit: Add newline when showing which commit was created The function log_tree_commit() does not break the line, so we have to do it ourselves. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- builtin-commit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index ee79cf1b72..2233300f40 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -494,6 +494,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) printf("Created %scommit ", initial_commit ? "initial " : ""); log_tree_commit(&rev, commit); + printf("\n"); } int git_commit_config(const char *k, const char *v) -- cgit v1.3 From ef12b50d0cf0123377a6fb96584a287a6c24346b Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Mon, 12 Nov 2007 15:48:22 -0500 Subject: Call refresh_cache() when updating the user index for --only commits. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're guaranteeing the user that the index will be stat-clean after git commit. Thus, we need to call refresh_cache() for the user index too, in the 'git commit ' case. Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 2233300f40..ee9fe72c61 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -109,6 +109,7 @@ static char *prepare_index(const char **files, const char *prefix) /* update the user index file */ add_files_to_cache(verbose, prefix, files); + refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close(fd)) die("unable to write new_index file"); -- cgit v1.3 From 18abc2dba4973c3c2cff286fac3340e95e0ee474 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Wed, 14 Nov 2007 10:31:53 -0500 Subject: builtin-commit: Clean up an unused variable and a debug fprintf(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index ee9fe72c61..5e2257c961 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -515,7 +515,7 @@ static const char commit_utf8_warn[] = int cmd_commit(int argc, const char **argv, const char *prefix) { - int header_len, parent_count = 0; + int header_len; struct strbuf sb; const char *index_file, *reflog_msg; char *nl; @@ -551,7 +551,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix) /* Determine parents */ if (initial_commit) { reflog_msg = "commit (initial)"; - parent_count = 0; } else if (amend) { struct commit_list *c; struct commit *commit; @@ -592,10 +591,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) /* Get the commit message and validate it */ header_len = sb.len; - if (!no_edit) { - fprintf(stderr, "launching editor, log %s\n", logfile); + if (!no_edit) launch_editor(git_path(commit_editmsg), &sb); - } else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) + else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) die("could not read commit message\n"); if (run_hook(index_file, "commit-msg", commit_editmsg)) exit(1); -- cgit v1.3 From bc5d248a9fba11cb78dd0a3a91938d881dec1245 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 18 Nov 2007 12:01:38 -0800 Subject: builtin-commit: do not color status output shown in the message template Noticed by Ping Yin on the list. Signed-off-by: Junio C Hamano --- builtin-commit.c | 5 ++++- wt-status.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 5e2257c961..7616dd152f 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -159,7 +159,7 @@ static const char sign_off_header[] = "Signed-off-by: "; static int prepare_log_message(const char *index_file, const char *prefix) { struct stat statbuf; - int commitable; + int commitable, saved_color_setting; struct strbuf sb; char *buffer; FILE *fp; @@ -243,7 +243,10 @@ static int prepare_log_message(const char *index_file, const char *prefix) if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); + saved_color_setting = wt_status_use_color; + wt_status_use_color = 0; commitable = run_status(fp, index_file, prefix); + wt_status_use_color = saved_color_setting; fclose(fp); diff --git a/wt-status.h b/wt-status.h index f58ebcbb23..225fb4d535 100644 --- a/wt-status.h +++ b/wt-status.h @@ -27,6 +27,7 @@ struct wt_status { }; int git_status_config(const char *var, const char *value); +int wt_status_use_color; void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); -- cgit v1.3 From e06ad5ffb9f8d4207d676fadd675cf1b949ce358 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 18 Nov 2007 12:21:17 -0800 Subject: builtin-commit: run commit-msg hook with correct message file It should run with $GIT_DIR/COMMIT_EDITMSG, not just COMMIT_EDITMSG. Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 7616dd152f..cd2f5cad1d 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -598,7 +598,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) launch_editor(git_path(commit_editmsg), &sb); else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) die("could not read commit message\n"); - if (run_hook(index_file, "commit-msg", commit_editmsg)) + if (run_hook(index_file, "commit-msg", git_path(commit_editmsg))) exit(1); stripspace(&sb, 1); if (sb.len < header_len || -- cgit v1.3 From 2888605c649ccd423232161186d72c0e6c458a48 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 18 Nov 2007 01:52:55 -0800 Subject: builtin-commit: fix partial-commit support When making a partial-commit, we need to prepare two index files, one to be used to write out the tree to be committed (temporary index) and the other to be used as the index file after the commit is made. The temporary index needs to be initialized to HEAD and then all the named paths on the command line need to be staged on top of the index. For this, running add_files_to_cache() that compares what is in the index and the paths given from the command line is not enough -- the comparison will miss the paths that the user previously ran "git add" to the index since the HEAD because the index reset to the HEAD would not know about them. The index file needs to get the same modification done when preparing the temporary index as described above. This implementation mimics the behaviour of the scripted version of git-commit. It first runs overlay_tree_on_cache(), which was stolen from ls-files with the earlier change, to get the list of paths that the user can potentially mean, and then uses pathspec_match() to find which ones the user meant. This list of paths is used to update both the temporary and the real index file. Additional fixes are: - read the index file after pre-commit hook returns, as the hook can modify it to affect the contents of the commit. - remove the temporary index file .git/next-index-* after commit is done or aborted. - run post-commit hook with the real index file to be used after the commit (previously it gave the temporary commit if a partial commit was made). - resurrect the safety mechanism to refuse partial commits during a merge to match the scripted version. Signed-off-by: Junio C Hamano --- builtin-commit.c | 242 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 40 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index cd2f5cad1d..e779db8ca3 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -7,6 +7,7 @@ #include "cache.h" #include "cache-tree.h" +#include "dir.h" #include "builtin.h" #include "diff.h" #include "diffcore.h" @@ -19,6 +20,7 @@ #include "strbuf.h" #include "utf8.h" #include "parse-options.h" +#include "path-list.h" static const char * const builtin_commit_usage[] = { "git-commit [options] [--] ...", @@ -28,7 +30,13 @@ static const char * const builtin_commit_usage[] = { static unsigned char head_sha1[20], merge_head_sha1[20]; static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; -static struct lock_file lock_file; +static struct lock_file index_lock; /* real index */ +static struct lock_file false_lock; /* used only for partial commits */ +static enum { + COMMIT_AS_IS = 1, + COMMIT_NORMAL, + COMMIT_PARTIAL, +} commit_style; static char *logfile, *force_author, *template_file; static char *edit_message, *use_message; @@ -78,41 +86,179 @@ static struct option builtin_commit_options[] = { OPT_END() }; +static void rollback_index_files(void) +{ + switch (commit_style) { + case COMMIT_AS_IS: + break; /* nothing to do */ + case COMMIT_NORMAL: + rollback_lock_file(&index_lock); + break; + case COMMIT_PARTIAL: + rollback_lock_file(&index_lock); + rollback_lock_file(&false_lock); + break; + } +} + +static void commit_index_files(void) +{ + switch (commit_style) { + case COMMIT_AS_IS: + break; /* nothing to do */ + case COMMIT_NORMAL: + commit_lock_file(&index_lock); + break; + case COMMIT_PARTIAL: + commit_lock_file(&index_lock); + rollback_lock_file(&false_lock); + break; + } +} + +/* + * Take a union of paths in the index and the named tree (typically, "HEAD"), + * and return the paths that match the given pattern in list. + */ +static int list_paths(struct path_list *list, const char *with_tree, + const char *prefix, const char **pattern) +{ + int i; + char *m; + + for (i = 0; pattern[i]; i++) + ; + m = xcalloc(1, i); + + if (with_tree) + overlay_tree_on_cache(with_tree, prefix); + + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (ce->ce_flags & htons(CE_UPDATE)) + continue; + if (!pathspec_match(pattern, m, ce->name, 0)) + continue; + path_list_insert(ce->name, list); + } + + return report_path_error(m, pattern, prefix ? strlen(prefix) : 0); +} + +static void add_remove_files(struct path_list *list) +{ + int i; + for (i = 0; i < list->nr; i++) { + struct path_list_item *p = &(list->items[i]); + if (file_exists(p->path)) + add_file_to_cache(p->path, 0); + else + remove_file_from_cache(p->path); + } +} + static char *prepare_index(const char **files, const char *prefix) { int fd; struct tree *tree; - struct lock_file *next_index_lock; + struct path_list partial; + const char **pathspec = NULL; if (interactive) { interactive_add(); + commit_style = COMMIT_AS_IS; return get_index_file(); } - fd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) die("index file corrupt"); - if (all || also) { - add_files_to_cache(verbose, also ? prefix : NULL, files); + if (*files) + pathspec = get_pathspec(prefix, files); + + /* + * Non partial, non as-is commit. + * + * (1) get the real index; + * (2) update the_index as necessary; + * (3) write the_index out to the real index (still locked); + * (4) return the name of the locked index file. + * + * The caller should run hooks on the locked real index, and + * (A) if all goes well, commit the real index; + * (B) on failure, rollback the real index. + */ + if (all || (also && pathspec && *pathspec)) { + int fd = hold_locked_index(&index_lock, 1); + add_files_to_cache(0, also ? prefix : NULL, pathspec); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close(fd)) die("unable to write new_index file"); - return lock_file.filename; + commit_style = COMMIT_NORMAL; + return index_lock.filename; } - if (*files == NULL) { - /* Commit index as-is. */ - rollback_lock_file(&lock_file); + /* + * As-is commit. + * + * (1) return the name of the real index file. + * + * The caller should run hooks on the real index, and run + * hooks on the real index, and create commit from the_index. + * We still need to refresh the index here. + */ + if (!pathspec || !*pathspec) { + fd = hold_locked_index(&index_lock, 1); + refresh_cache(REFRESH_QUIET); + if (write_cache(fd, active_cache, active_nr) || + close(fd) || commit_locked_index(&index_lock)) + die("unable to write new_index file"); + commit_style = COMMIT_AS_IS; return get_index_file(); } - /* update the user index file */ - add_files_to_cache(verbose, prefix, files); + /* + * A partial commit. + * + * (0) find the set of affected paths; + * (1) get lock on the real index file; + * (2) update the_index with the given paths; + * (3) write the_index out to the real index (still locked); + * (4) get lock on the false index file; + * (5) reset the_index from HEAD; + * (6) update the_index the same way as (2); + * (7) write the_index out to the false index file; + * (8) return the name of the false index file (still locked); + * + * The caller should run hooks on the locked false index, and + * create commit from it. Then + * (A) if all goes well, commit the real index; + * (B) on failure, rollback the real index; + * In either case, rollback the false index. + */ + commit_style = COMMIT_PARTIAL; + + if (file_exists(git_path("MERGE_HEAD"))) + die("cannot do a partial commit during a merge."); + + memset(&partial, 0, sizeof(partial)); + partial.strdup_paths = 1; + if (list_paths(&partial, initial_commit ? NULL : "HEAD", prefix, pathspec)) + exit(1); + + discard_cache(); + if (read_cache() < 0) + die("cannot read the index"); + + fd = hold_locked_index(&index_lock, 1); + add_remove_files(&partial); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close(fd)) die("unable to write new_index file"); + fd = hold_lock_file_for_update(&false_lock, + git_path("next-index-%d", getpid()), 1); + discard_cache(); if (!initial_commit) { tree = parse_tree_indirect(head_sha1); if (!tree) @@ -120,17 +266,12 @@ static char *prepare_index(const char **files, const char *prefix) if (read_tree(tree, 0, NULL)) die("failed to read HEAD tree object"); } - - /* Use a lock file to garbage collect the temporary index file. */ - next_index_lock = xmalloc(sizeof(*next_index_lock)); - fd = hold_lock_file_for_update(next_index_lock, - git_path("next-index-%d", getpid()), 1); - add_files_to_cache(verbose, prefix, files); + add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr) || close(fd)) - die("unable to write new_index file"); - return next_index_lock->filename; + if (write_cache(fd, active_cache, active_nr) || close(fd)) + die("unable to write temporary index file"); + return false_lock.filename; } static int run_status(FILE *fp, const char *index_file, const char *prefix) @@ -441,7 +582,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) commitable = run_status(stdout, index_file, prefix); - rollback_lock_file(&lock_file); + rollback_index_files(); return commitable ? 0 : 1; } @@ -531,23 +672,36 @@ int cmd_commit(int argc, const char **argv, const char *prefix) index_file = prepare_index(argv, prefix); - if (!no_verify && run_hook(index_file, "pre-commit", NULL)) - exit(1); + if (!no_verify && run_hook(index_file, "pre-commit", NULL)) { + rollback_index_files(); + return 1; + } if (!prepare_log_message(index_file, prefix) && !in_merge) { run_status(stdout, index_file, prefix); + rollback_index_files(); unlink(commit_editmsg); return 1; } - strbuf_init(&sb, 0); - - /* Start building up the commit header */ + /* + * Re-read the index as pre-commit hook could have updated it, + * and write it out as a tree. + */ + discard_cache(); read_cache_from(index_file); - active_cache_tree = cache_tree(); + if (!active_cache_tree) + active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, - active_cache, active_nr, 0, 0) < 0) + active_cache, active_nr, 0, 0) < 0) { + rollback_index_files(); die("Error building trees"); + } + + /* + * The commit object + */ + strbuf_init(&sb, 0); strbuf_addf(&sb, "tree %s\n", sha1_to_hex(active_cache_tree->sha1)); @@ -596,20 +750,27 @@ int cmd_commit(int argc, const char **argv, const char *prefix) header_len = sb.len; if (!no_edit) launch_editor(git_path(commit_editmsg), &sb); - else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) + else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { + rollback_index_files(); die("could not read commit message\n"); - if (run_hook(index_file, "commit-msg", git_path(commit_editmsg))) + } + if (run_hook(index_file, "commit-msg", git_path(commit_editmsg))) { + rollback_index_files(); exit(1); + } stripspace(&sb, 1); - if (sb.len < header_len || - message_is_empty(&sb, header_len)) + if (sb.len < header_len || message_is_empty(&sb, header_len)) { + rollback_index_files(); die("* no commit message? aborting commit."); + } strbuf_addch(&sb, '\0'); if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf)) fprintf(stderr, commit_utf8_warn); - if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) + if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) { + rollback_index_files(); die("failed to write commit object"); + } ref_lock = lock_any_ref_for_update("HEAD", initial_commit ? NULL : head_sha1, @@ -624,21 +785,22 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg)); strbuf_insert(&sb, strlen(reflog_msg), ": ", 2); - if (!ref_lock) + if (!ref_lock) { + rollback_index_files(); die("cannot lock HEAD ref"); - if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) + } + if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0) { + rollback_index_files(); die("cannot update HEAD ref"); + } unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); - if (lock_file.filename[0] && commit_locked_index(&lock_file)) - die("failed to write new index"); + commit_index_files(); rerere(); - - run_hook(index_file, "post-commit", NULL); - + run_hook(get_index_file(), "post-commit", NULL); if (!quiet) print_summary(prefix, commit_sha1); -- cgit v1.3 From 99a12694582e2148fcd492f1eedaddcfe2a21621 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Wed, 21 Nov 2007 21:54:49 -0500 Subject: builtin-commit: Include the diff in the commit message when verbose. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit run_diff_index() and the entire diff machinery is hard coded to output to stdout, so just redirect that and restore it when done. Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 8 +++++++- wt-status.c | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index e779db8ca3..4de316a366 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -662,7 +662,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) int header_len; struct strbuf sb; const char *index_file, *reflog_msg; - char *nl; + char *nl, *p; unsigned char commit_sha1[20]; struct ref_lock *ref_lock; @@ -758,6 +758,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) rollback_index_files(); exit(1); } + + /* Truncate the message just before the diff, if any. */ + p = strstr(sb.buf, "\ndiff --git a/"); + if (p != NULL) + strbuf_setlen(&sb, p - sb.buf); + stripspace(&sb, 1); if (sb.len < header_len || message_is_empty(&sb, header_len)) { rollback_index_files(); diff --git a/wt-status.c b/wt-status.c index d3c10b8b8d..0e0439f2c2 100644 --- a/wt-status.c +++ b/wt-status.c @@ -315,12 +315,28 @@ static void wt_status_print_untracked(struct wt_status *s) static void wt_status_print_verbose(struct wt_status *s) { struct rev_info rev; + int saved_stdout; + + fflush(s->fp); + + /* Sigh, the entire diff machinery is hardcoded to output to + * stdout. Do the dup-dance...*/ + saved_stdout = dup(STDOUT_FILENO); + if (saved_stdout < 0 ||dup2(fileno(s->fp), STDOUT_FILENO) < 0) + die("couldn't redirect stdout\n"); + init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, s->reference); rev.diffopt.output_format |= DIFF_FORMAT_PATCH; rev.diffopt.detect_rename = 1; wt_read_cache(s); run_diff_index(&rev, 1); + + fflush(stdout); + + if (dup2(saved_stdout, STDOUT_FILENO) < 0) + die("couldn't restore stdout\n"); + close(saved_stdout); } void wt_status_print(struct wt_status *s) -- cgit v1.3 From 3f061887c562b20d3ed3d1f764462cf986a1ad12 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 25 Nov 2007 10:10:10 -0800 Subject: add -i: Fix running from a subdirectory This fixes the pathspec interactive_add() passes to the underlying git-add--interactive helper. When the command was run from a subdirectory, cmd_add() already has gone up to the toplevel of the work tree, and the helper will be spawned from there. The pathspec given on the command line from the user needs to be adjusted for this. This adds "validate_pathspec()" function in the callchain, but it does not validate yet. The function can be changed to barf if there are unmatching pathspec given by the user, but that is not strictly necessary. Signed-off-by: Junio C Hamano --- builtin-add.c | 24 ++++++++++++++++++++---- builtin-commit.c | 2 +- commit.h | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-add.c b/builtin-add.c index 7c6a296af1..865c475ec9 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -135,13 +135,29 @@ static void refresh(int verbose, const char **pathspec) free(seen); } -int interactive_add(int argc, const char **argv) +static const char **validate_pathspec(int argc, const char **argv, const char *prefix) +{ + const char **pathspec = get_pathspec(prefix, argv); + + return pathspec; +} + +int interactive_add(int argc, const char **argv, const char *prefix) { int status; - const char **args = xcalloc(sizeof(const char *), (argc + 2)); + const char **args; + const char **pathspec = NULL; + + if (argc) { + pathspec = validate_pathspec(argc, argv, prefix); + if (!pathspec) + return -1; + } + args = xcalloc(sizeof(const char *), (argc + 2)); args[0] = "add--interactive"; - memcpy(&(args[1]), argv, sizeof(const char *) * argc); + if (argc) + memcpy(&(args[1]), pathspec, sizeof(const char *) * argc); args[argc + 1] = NULL; status = run_command_v_opt(args, RUN_GIT_CMD); @@ -177,7 +193,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, builtin_add_options, builtin_add_usage, 0); if (add_interactive) - exit(interactive_add(argc, argv)); + exit(interactive_add(argc, argv, prefix)); git_config(git_default_config); diff --git a/builtin-commit.c b/builtin-commit.c index 5d27102a62..45e51b1d5f 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -165,7 +165,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) const char **pathspec = NULL; if (interactive) { - interactive_add(argc, argv); + interactive_add(argc, argv, prefix); commit_style = COMMIT_AS_IS; return get_index_file(); } diff --git a/commit.h b/commit.h index 9f0765bd9c..10e2b5d4cf 100644 --- a/commit.h +++ b/commit.h @@ -113,7 +113,7 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads, int in_merge_bases(struct commit *, struct commit **, int); -extern int interactive_add(int argc, const char **argv); +extern int interactive_add(int argc, const char **argv, const char *prefix); extern int rerere(void); static inline int single_parent(struct commit *commit) -- cgit v1.3 From 8babab95af7c01d9ea75c97ee0df40e5a2170b83 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 26 Nov 2007 09:59:27 +0100 Subject: builtin-commit.c: export GIT_INDEX_FILE for launch_editor as well. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The editor program to let the user edit the log message used to get GIT_INDEX_FILE environment variable pointing at the right file, but this was lost when git-commit was rewritten in C. Signed-off-by: Pierre Habouzit Acked-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 9 ++++++--- builtin-tag.c | 6 +++--- strbuf.h | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 4de316a366..f60bd7f4dc 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -748,9 +748,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix) /* Get the commit message and validate it */ header_len = sb.len; - if (!no_edit) - launch_editor(git_path(commit_editmsg), &sb); - else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { + if (!no_edit) { + 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), &sb, env); + } else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { rollback_index_files(); die("could not read commit message\n"); } diff --git a/builtin-tag.c b/builtin-tag.c index 566b9d186f..7626da3f47 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -17,7 +17,7 @@ static const char builtin_tag_usage[] = static char signingkey[1000]; -void launch_editor(const char *path, struct strbuf *buffer) +void launch_editor(const char *path, struct strbuf *buffer, const char *const *env) { const char *editor, *terminal; @@ -43,7 +43,7 @@ void launch_editor(const char *path, struct strbuf *buffer) if (strcmp(editor, ":")) { const char *args[] = { editor, path, NULL }; - if (run_command_v_opt(args, 0)) + if (run_command_v_opt_cd_env(args, 0, NULL, env)) die("There was a problem with the editor %s.", editor); } @@ -312,7 +312,7 @@ static void create_tag(const unsigned char *object, const char *tag, write_or_die(fd, tag_template, strlen(tag_template)); close(fd); - launch_editor(path, buf); + launch_editor(path, buf, NULL); unlink(path); free(path); diff --git a/strbuf.h b/strbuf.h index 8334a9bad0..36d61db657 100644 --- a/strbuf.h +++ b/strbuf.h @@ -117,6 +117,6 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); extern int strbuf_getline(struct strbuf *, FILE *, int); extern void stripspace(struct strbuf *buf, int skip_comments); -extern void launch_editor(const char *path, struct strbuf *buffer); +extern void launch_editor(const char *path, struct strbuf *buffer, const char *const *env); #endif /* STRBUF_H */ -- cgit v1.3 From a98b819183820cf87f1073c36b57883cb05e7049 Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Mon, 26 Nov 2007 10:16:08 -0500 Subject: Fix off-by-one error when truncating the diff out of the commit message. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kristian Høgsberg Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index f60bd7f4dc..a35881e20b 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -765,7 +765,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) /* Truncate the message just before the diff, if any. */ p = strstr(sb.buf, "\ndiff --git a/"); if (p != NULL) - strbuf_setlen(&sb, p - sb.buf); + strbuf_setlen(&sb, p - sb.buf + 1); stripspace(&sb, 1); if (sb.len < header_len || message_is_empty(&sb, header_len)) { -- cgit v1.3 From 7168624c3530d8c7ee32f930f8fb2ba302b9801f Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 28 Nov 2007 22:13:08 +0100 Subject: Do not generate full commit log message if it is not going to be used Like when it is already specified through -C, -F or -m to git-commit. Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-commit.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index a35881e20b..1a9a256881 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -367,6 +367,28 @@ static int prepare_log_message(const char *index_file, const char *prefix) strbuf_release(&sb); + if (no_edit) { + struct rev_info rev; + unsigned char sha1[40]; + + fclose(fp); + + if (!active_nr && read_cache() < 0) + die("Cannot read index"); + + if (get_sha1("HEAD", sha1) != 0) + return !!active_nr; + + init_revisions(&rev, ""); + rev.abbrev = 0; + setup_revisions(0, NULL, &rev, "HEAD"); + DIFF_OPT_SET(&rev.diffopt, QUIET); + DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS); + run_diff_index(&rev, 1 /* cached */); + + return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); + } + if (in_merge && !no_edit) fprintf(fp, "#\n" -- cgit v1.3 From b5b644a93adb41bca590a3cdfd9b64ccf3614f50 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 2 Dec 2007 01:07:03 -0500 Subject: git-commit: clean up die messages These are three types of cleanups here: 1. remove newline from die message (die/report adds it already) 2. typo: s/merger/merge/ 3. the old "* no commit message? aborting commit." is now prepended with "fatal: ", making the asterisk look a little funny. Let's just remove it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 1a9a256881..6c1ace32a4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -336,7 +336,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) - die("could not open %s\n", git_path(commit_editmsg)); + die("could not open %s", git_path(commit_editmsg)); stripspace(&sb, 0); @@ -362,8 +362,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) - die("could not write commit template: %s\n", - strerror(errno)); + die("could not write commit template: %s", strerror(errno)); strbuf_release(&sb); @@ -470,13 +469,13 @@ static void determine_author_info(struct strbuf *sb) a = strstr(use_message_buffer, "\nauthor "); if (!a) - die("invalid commit: %s\n", use_message); + die("invalid commit: %s", use_message); lb = strstr(a + 8, " <"); rb = strstr(a + 8, "> "); eol = strchr(a + 8, '\n'); if (!lb || !rb || !eol) - die("invalid commit: %s\n", use_message); + die("invalid commit: %s", use_message); name = xstrndup(a + 8, lb - (a + 8)); email = xstrndup(lb + 2, rb - (lb + 2)); @@ -488,7 +487,7 @@ static void determine_author_info(struct strbuf *sb) const char *rb = strchr(force_author, '>'); if (!lb || !rb) - die("malformed --author parameter\n"); + die("malformed --author parameter"); name = xstrndup(force_author, lb - force_author); email = xstrndup(lb + 2, rb - (lb + 2)); } @@ -518,7 +517,7 @@ static int parse_and_validate_options(int argc, const char *argv[]) if (amend && initial_commit) die("You have nothing to amend."); if (amend && in_merge) - die("You are in the middle of a merger -- cannot amend."); + die("You are in the middle of a merge -- cannot amend."); if (use_message) f++; @@ -641,7 +640,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) commit = lookup_commit(sha1); if (!commit) - die("couldn't look up newly created commit\n"); + die("couldn't look up newly created commit"); if (!commit || parse_commit(commit)) die("could not parse newly created commit"); @@ -777,7 +776,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) launch_editor(git_path(commit_editmsg), &sb, env); } else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { rollback_index_files(); - die("could not read commit message\n"); + die("could not read commit message"); } if (run_hook(index_file, "commit-msg", git_path(commit_editmsg))) { rollback_index_files(); @@ -792,7 +791,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) stripspace(&sb, 1); if (sb.len < header_len || message_is_empty(&sb, header_len)) { rollback_index_files(); - die("* no commit message? aborting commit."); + die("no commit message? aborting commit."); } strbuf_addch(&sb, '\0'); if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf)) -- cgit v1.3 From d9ccfe7711a8bf1ed9d9cd87daa9863e0d564b23 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 2 Dec 2007 13:43:34 -0800 Subject: Fix --signoff in builtin-commit differently. Introduce fmt_name() specifically meant for formatting the name and email pair, to add signed-off-by value. This reverts parts of 13208572fbe8838fd8835548d7502202d1f7b21d (builtin-commit: fix --signoff) so that an empty datestamp string given to fmt_ident() by mistake will error out as before. Signed-off-by: Junio C Hamano --- builtin-commit.c | 6 ++---- cache.h | 1 + ident.c | 34 ++++++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 14 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 6c1ace32a4..05594f2b13 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -346,11 +346,9 @@ static int prepare_log_message(const char *index_file, const char *prefix) strbuf_init(&sob, 0); strbuf_addstr(&sob, sign_off_header); - strbuf_addstr(&sob, fmt_ident(getenv("GIT_COMMITTER_NAME"), - getenv("GIT_COMMITTER_EMAIL"), - "", 1)); + 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)) { diff --git a/cache.h b/cache.h index cf0bdc674c..43cfebb0cf 100644 --- a/cache.h +++ b/cache.h @@ -444,6 +444,7 @@ enum date_mode parse_date_format(const char *format); extern const char *git_author_info(int); extern const char *git_committer_info(int); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); +extern const char *fmt_name(const char *name, const char *email); struct checkout { const char *base_dir; diff --git a/ident.c b/ident.c index 5be7533ffd..021d79b38b 100644 --- a/ident.c +++ b/ident.c @@ -192,12 +192,14 @@ static const char *env_hint = "Omit --global to set the identity only in this repository.\n" "\n"; -const char *fmt_ident(const char *name, const char *email, - const char *date_str, int error_on_no_name) +static const char *fmt_ident_1(const char *name, const char *email, + const char *date_str, int flag) { static char buffer[1000]; char date[50]; int i; + int error_on_no_name = !!(flag & 01); + int name_addr_only = !!(flag & 02); setup_ident(); if (!name) @@ -224,24 +226,36 @@ const char *fmt_ident(const char *name, const char *email, } strcpy(date, git_default_date); - if (date_str) { - if (*date_str) - parse_date(date_str, date, sizeof(date)); - else - date[0] = '\0'; - } + if (!name_addr_only && date_str) + parse_date(date_str, date, sizeof(date)); i = copy(buffer, sizeof(buffer), 0, name); i = add_raw(buffer, sizeof(buffer), i, " <"); i = copy(buffer, sizeof(buffer), i, email); - i = add_raw(buffer, sizeof(buffer), i, date[0] ? "> " : ">"); - i = copy(buffer, sizeof(buffer), i, date); + if (!name_addr_only) { + i = add_raw(buffer, sizeof(buffer), i, "> "); + i = copy(buffer, sizeof(buffer), i, date); + } else { + i = add_raw(buffer, sizeof(buffer), i, ">"); + } if (i >= sizeof(buffer)) die("Impossibly long personal identifier"); buffer[i] = 0; return buffer; } +const char *fmt_ident(const char *name, const char *email, + const char *date_str, int error_on_no_name) +{ + int flag = (error_on_no_name ? 01 : 0); + return fmt_ident_1(name, email, date_str, flag); +} + +const char *fmt_name(const char *name, const char *email) +{ + return fmt_ident_1(name, email, NULL, 03); +} + const char *git_author_info(int error_on_no_name) { return fmt_ident(getenv("GIT_AUTHOR_NAME"), -- cgit v1.3 From 2f02b25f36bce23e6b65c5112876796a56e084ca Mon Sep 17 00:00:00 2001 From: Shawn Bohrer Date: Sun, 2 Dec 2007 23:02:09 -0600 Subject: Make git status usage say git status instead of git commit git status shares the same usage information as git commit since it shows what would be committed if the same options are given. However, when displaying the usage information for git status it should say it is for git status not git commit. Signed-off-by: Shawn Bohrer Signed-off-by: Junio C Hamano --- builtin-commit.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 05594f2b13..f37a90f078 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -27,6 +27,11 @@ static const char * const builtin_commit_usage[] = { NULL }; +static const char * const builtin_status_usage[] = { + "git-status [options] [--] ...", + NULL +}; + static unsigned char head_sha1[20], merge_head_sha1[20]; static char *use_message_buffer; static const char commit_editmsg[] = "COMMIT_EDITMSG"; @@ -493,12 +498,12 @@ static void determine_author_info(struct strbuf *sb) strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, 1)); } -static int parse_and_validate_options(int argc, const char *argv[]) +static int parse_and_validate_options(int argc, const char *argv[], + const char * const usage[]) { int f = 0; - argc = parse_options(argc, argv, builtin_commit_options, - builtin_commit_usage, 0); + argc = parse_options(argc, argv, builtin_commit_options, usage, 0); if (logfile || message.len || use_message) no_edit = 1; @@ -595,7 +600,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) git_config(git_status_config); - argc = parse_and_validate_options(argc, argv); + argc = parse_and_validate_options(argc, argv, builtin_status_usage); index_file = prepare_index(argv, prefix); @@ -687,7 +692,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) git_config(git_commit_config); - argc = parse_and_validate_options(argc, argv); + argc = parse_and_validate_options(argc, argv, builtin_commit_usage); index_file = prepare_index(argv, prefix); -- cgit v1.3 From 9663c3bc6a04b9b4f63a54b820d3edb16aa95e6d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 2 Dec 2007 23:55:23 -0800 Subject: git-commit: Allow to amend a merge commit that does not change the tree Normally, it should not be allowed to generate an empty commit. A merge commit generated with git 'merge -s ours' does not change the tree (along the first parent), but merges are not "empty" even if they do not change the tree. Hence, we should be careful not to forbid this case. Signed-off-by: Junio C Hamano --- builtin-commit.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index f37a90f078..6c2dc390c4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -676,6 +676,14 @@ int git_commit_config(const char *k, const char *v) return git_status_config(k, v); } +static int is_a_merge(const unsigned char *sha1) +{ + struct commit *commit = lookup_commit(sha1); + if (!commit || parse_commit(commit)) + die("could not parse HEAD commit"); + return !!(commit->parents && commit->parents->next); +} + static const char commit_utf8_warn[] = "Warning: commit message does not conform to UTF-8.\n" "You may want to amend it after fixing the message, or set the config\n" @@ -701,7 +709,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) return 1; } - if (!prepare_log_message(index_file, prefix) && !in_merge) { + if (!prepare_log_message(index_file, prefix) && !in_merge && + !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix); rollback_index_files(); unlink(commit_editmsg); -- cgit v1.3 From 5241b6bfe2285a6da598a0348c37b77964035bc8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 3 Dec 2007 00:03:10 -0800 Subject: git-commit --allow-empty It does not usually make sense to record a commit that has the exact same tree as its sole parent commit and that is why git-commit prevents you from making such a mistake, but when data from foreign scm is involved, it is a different story. We are equipped to represent such an (perhaps insane, perhaps by mistake, or perhaps done on purpose) empty change, and it is better to represent it bypassing the safety valve for native use. This is primarily for use by foreign scm interface scripts. Signed-off-by: Junio C Hamano --- builtin-commit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 6c2dc390c4..e635d9963b 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -46,7 +46,7 @@ static enum { static char *logfile, *force_author, *template_file; static char *edit_message, *use_message; static int all, edit_flag, also, interactive, only, amend, signoff; -static int quiet, verbose, untracked_files, no_verify; +static int quiet, verbose, untracked_files, no_verify, allow_empty; static int no_edit, initial_commit, in_merge; const char *only_include_assumed; @@ -87,6 +87,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"), + OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), OPT_END() }; @@ -710,7 +711,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } if (!prepare_log_message(index_file, prefix) && !in_merge && - !(amend && is_a_merge(head_sha1))) { + !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix); rollback_index_files(); unlink(commit_editmsg); -- cgit v1.3 From 46f721c8fee9f1c027f96e2bf987ce6e7d05ab94 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Fri, 7 Dec 2007 16:26:07 -0500 Subject: add status.relativePaths config variable The output of git-status was recently changed to output relative paths. Setting this variable to false restores the old behavior for any old-timers that prefer it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- Documentation/config.txt | 6 ++++++ Documentation/git-status.txt | 7 ++++++- builtin-commit.c | 3 ++- t/t7502-status.sh | 31 +++++++++++++++++++++++++++++++ wt-status.c | 6 ++++++ wt-status.h | 1 + 6 files changed, 52 insertions(+), 2 deletions(-) (limited to 'builtin-commit.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index 736fcd71cc..79d51f26cc 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -762,6 +762,12 @@ showbranch.default:: The default set of branches for gitlink:git-show-branch[1]. See gitlink:git-show-branch[1]. +status.relativePaths:: + By default, gitlink:git-status[1] shows paths relative to the + current directory. Setting this variable to `false` shows paths + relative to the repository root (this was the default for git + prior to v1.5.4). + tar.umask:: This variable can be used to restrict the permission bits of tar archive entries. The default is 0002, which turns off the diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt index b0cb6bc8b7..645dc85ceb 100644 --- a/Documentation/git-status.txt +++ b/Documentation/git-status.txt @@ -42,7 +42,8 @@ template comments, and all the output lines are prefixed with '#'. The paths mentioned in the output, unlike many other git commands, are made relative to the current directory, if you are working in a -subdirectory (this is on purpose, to help cutting and pasting). +subdirectory (this is on purpose, to help cutting and pasting). See +the status.relativePaths config option below. CONFIGURATION @@ -53,6 +54,10 @@ mean the same thing and the latter is kept for backward compatibility) and `color.status.` configuration variables to colorize its output. +If the config variable `status.relativePaths` is set to false, then all +paths shown are relative to the repository root, not to the current +directory. + See Also -------- gitlink:gitignore[5] diff --git a/builtin-commit.c b/builtin-commit.c index 2ec8223132..19297ac027 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -285,7 +285,8 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix) struct wt_status s; wt_status_prepare(&s); - s.prefix = prefix; + if (wt_status_relative_paths) + s.prefix = prefix; if (amend) { s.amend = 1; diff --git a/t/t7502-status.sh b/t/t7502-status.sh index d6ae69d46e..9ce50cade8 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -88,4 +88,35 @@ test_expect_success 'status with relative paths' ' ' +cat > expect << \EOF +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# new file: dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# dir1/untracked +# dir2/modified +# dir2/untracked +# expect +# output +# untracked +EOF + +test_expect_success 'status without relative paths' ' + + git config status.relativePaths false + (cd dir1 && git status) > output && + git diff expect output + +' + test_done diff --git a/wt-status.c b/wt-status.c index 05414bb9e9..51c1879691 100644 --- a/wt-status.c +++ b/wt-status.c @@ -8,6 +8,7 @@ #include "revision.h" #include "diffcore.h" +int wt_status_relative_paths = 1; int wt_status_use_color = 0; static char wt_status_colors[][COLOR_MAXLEN] = { "", /* WT_STATUS_HEADER: normal */ @@ -400,6 +401,11 @@ int git_status_config(const char *k, const char *v) if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { int slot = parse_status_slot(k, 13); color_parse(v, k, wt_status_colors[slot]); + return 0; + } + if (!strcmp(k, "status.relativepaths")) { + wt_status_relative_paths = git_config_bool(k, v); + return 0; } return git_default_config(k, v); } diff --git a/wt-status.h b/wt-status.h index 225fb4d535..63d50f2871 100644 --- a/wt-status.h +++ b/wt-status.h @@ -28,6 +28,7 @@ struct wt_status { int git_status_config(const char *var, const char *value); int wt_status_use_color; +int wt_status_relative_paths; void wt_status_prepare(struct wt_status *s); void wt_status_print(struct wt_status *s); -- cgit v1.3 From 6b95655d7d2a5378e409ea0754b9b8d32ed939f8 Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Sat, 8 Dec 2007 12:38:07 +0100 Subject: Allow --no-verify to bypass commit-msg hook At the moment the --no-verify switch to "git commit" instructs it to skip over the pre-commit hook. Here we teach "git commit --no-verify" to skip over the commit-msg hook as well. This brings the behaviour of builtin-commit back in line with git-commit.sh. Signed-off-by: Wincent Colaiuta Signed-off-by: Junio C Hamano --- builtin-commit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 19297ac027..2032ca314c 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -792,7 +792,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) rollback_index_files(); die("could not read commit message"); } - if (run_hook(index_file, "commit-msg", git_path(commit_editmsg))) { + if (!no_verify && + run_hook(index_file, "commit-msg", git_path(commit_editmsg))) { rollback_index_files(); exit(1); } -- cgit v1.3 From 740001a5780a12972c83c99f25c49c8d8cebdb43 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 8 Dec 2007 23:23:20 -0800 Subject: Fix commit-msg hook to allow editing The old git-commit.sh script allowed the commit-msg hook to not only prevent a commit from proceding, but also to edit the commit message on the fly and allow it to proceed. So here we teach builtin-commit to do the same. This is based on Wincent's patch, but redone with a clarified logic. Signed-off-by: Junio C Hamano --- builtin-commit.c | 9 +++++---- builtin-tag.c | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 2032ca314c..30a9debcda 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -787,16 +787,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix) 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), &sb, env); - } else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { - rollback_index_files(); - die("could not read commit message"); + launch_editor(git_path(commit_editmsg), NULL, env); } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg))) { rollback_index_files(); exit(1); } + if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { + rollback_index_files(); + die("could not read commit message"); + } /* Truncate the message just before the diff, if any. */ p = strstr(sb.buf, "\ndiff --git a/"); diff --git a/builtin-tag.c b/builtin-tag.c index 729389bbd6..9f966fc883 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -53,6 +53,8 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e die("There was a problem with the editor %s.", editor); } + if (!buffer) + return; if (strbuf_read_file(buffer, path, 0) < 0) die("could not read message file '%s': %s", path, strerror(errno)); -- cgit v1.3 From 774751a8bc594a5b56039bbdc43c45e3882dd804 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 8 Dec 2007 17:32:08 -0800 Subject: Re-fix "builtin-commit: fix --signoff" An earlier fix to the said commit was incomplete; it mixed up the meaning of the flag parameter passed to the internal fmt_ident() function, so this corrects it. git_author_info() and git_committer_info() can be told to issue a warning when no usable user information is found, and optionally can be told to error out. Operations that actually use the information to record a new commit or a tag will still error out, but the caller to leave reflog record will just silently use bogus user information. Not warning on misconfigured user information while writing a reflog entry is somewhat debatable, but it is probably nicer to the users to silently let it pass, because the only information you are losing is who checked out the branch. * git_author_info() and git_committer_info() used to take 1 (positive int) to error out with a warning on misconfiguration; this is now signalled with a symbolic constant IDENT_ERROR_ON_NO_NAME. * These functions used to take -1 (negative int) to warn but continue; this is now signalled with a symbolic constant IDENT_WARN_ON_NO_NAME. * fmt_ident() function implements the above error reporting behaviour common to git_author_info() and git_committer_info(). A symbolic constant IDENT_NO_DATE can be or'ed in to the flag parameter to make it return only the "Name ". * fmt_name() is a thin wrapper around fmt_ident() that always passes IDENT_ERROR_ON_NO_NAME and IDENT_NO_DATE. Signed-off-by: Junio C Hamano --- builtin-commit-tree.c | 4 ++-- builtin-commit.c | 4 ++-- builtin-log.c | 4 ++-- builtin-tag.c | 4 ++-- cache.h | 3 +++ ident.c | 30 ++++++++++++------------------ refs.c | 2 +- var.c | 4 ++-- 8 files changed, 26 insertions(+), 29 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 88b0ab36eb..6610d18358 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -98,8 +98,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) strbuf_addf(&buffer, "parent %s\n", sha1_to_hex(parent_sha1[i])); /* Person/date information */ - strbuf_addf(&buffer, "author %s\n", git_author_info(1)); - strbuf_addf(&buffer, "committer %s\n", git_committer_info(1)); + strbuf_addf(&buffer, "author %s\n", git_author_info(IDENT_ERROR_ON_NO_NAME)); + strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); if (!encoding_is_utf8) strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding); strbuf_addch(&buffer, '\n'); diff --git a/builtin-commit.c b/builtin-commit.c index 30a9debcda..b6b81d531d 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -497,7 +497,7 @@ static void determine_author_info(struct strbuf *sb) email = xstrndup(lb + 2, rb - (lb + 2)); } - strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, 1)); + strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, IDENT_ERROR_ON_NO_NAME)); } static int parse_and_validate_options(int argc, const char *argv[], @@ -776,7 +776,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) } determine_author_info(&sb); - strbuf_addf(&sb, "committer %s\n", git_committer_info(1)); + strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); if (!is_encoding_utf8(git_commit_encoding)) strbuf_addf(&sb, "encoding %s\n", git_commit_encoding); strbuf_addch(&sb, '\n'); diff --git a/builtin-log.c b/builtin-log.c index e1f1cf6714..b6a11220e2 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -557,7 +557,7 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha static void gen_message_id(char *dest, unsigned int length, char *base) { - const char *committer = git_committer_info(-1); + const char *committer = git_committer_info(IDENT_WARN_ON_NO_NAME); const char *email_start = strrchr(committer, '<'); const char *email_end = strrchr(committer, '>'); if(!email_start || !email_end || email_start > email_end - 1) @@ -665,7 +665,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) !strcmp(argv[i], "-s")) { const char *committer; const char *endpos; - committer = git_committer_info(1); + committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); endpos = strchr(committer, '>'); if (!endpos) die("bogos committer info %s\n", committer); diff --git a/builtin-tag.c b/builtin-tag.c index 9f966fc883..517419fd3d 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -188,7 +188,7 @@ static int do_sign(struct strbuf *buffer) int len; if (!*signingkey) { - if (strlcpy(signingkey, git_committer_info(1), + if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME), sizeof(signingkey)) > sizeof(signingkey) - 1) return error("committer info too long."); bracket = strchr(signingkey, '>'); @@ -298,7 +298,7 @@ static void create_tag(const unsigned char *object, const char *tag, sha1_to_hex(object), typename(type), tag, - git_committer_info(1)); + git_committer_info(IDENT_ERROR_ON_NO_NAME)); if (header_len > sizeof(header_buf) - 1) die("tag header too big."); diff --git a/cache.h b/cache.h index 406befb705..c6142e9b7a 100644 --- a/cache.h +++ b/cache.h @@ -453,6 +453,9 @@ void datestamp(char *buf, int bufsize); unsigned long approxidate(const char *); enum date_mode parse_date_format(const char *format); +#define IDENT_WARN_ON_NO_NAME 1 +#define IDENT_ERROR_ON_NO_NAME 2 +#define IDENT_NO_DATE 4 extern const char *git_author_info(int); extern const char *git_committer_info(int); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); diff --git a/ident.c b/ident.c index 7631698f27..892d77ac93 100644 --- a/ident.c +++ b/ident.c @@ -182,14 +182,15 @@ static const char *env_hint = "Omit --global to set the identity only in this repository.\n" "\n"; -static const char *fmt_ident_1(const char *name, const char *email, - const char *date_str, int flag) +const char *fmt_ident(const char *name, const char *email, + const char *date_str, int flag) { static char buffer[1000]; char date[50]; int i; - int error_on_no_name = !!(flag & 01); - int name_addr_only = !!(flag & 02); + int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME); + int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME); + int name_addr_only = (flag & IDENT_NO_DATE); setup_ident(); if (!name) @@ -200,12 +201,12 @@ static const char *fmt_ident_1(const char *name, const char *email, if (!*name) { struct passwd *pw; - if (0 <= error_on_no_name && + if ((warn_on_no_name || error_on_no_name) && name == git_default_name && env_hint) { fprintf(stderr, env_hint, au_env, co_env); env_hint = NULL; /* warn only once, for "git-var -l" */ } - if (0 < error_on_no_name) + if (error_on_no_name) die("empty ident %s <%s> not allowed", name, email); pw = getpwuid(getuid()); if (!pw) @@ -234,30 +235,23 @@ static const char *fmt_ident_1(const char *name, const char *email, return buffer; } -const char *fmt_ident(const char *name, const char *email, - const char *date_str, int error_on_no_name) -{ - int flag = (error_on_no_name ? 01 : 0); - return fmt_ident_1(name, email, date_str, flag); -} - const char *fmt_name(const char *name, const char *email) { - return fmt_ident_1(name, email, NULL, 03); + return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE); } -const char *git_author_info(int error_on_no_name) +const char *git_author_info(int flag) { return fmt_ident(getenv("GIT_AUTHOR_NAME"), getenv("GIT_AUTHOR_EMAIL"), getenv("GIT_AUTHOR_DATE"), - error_on_no_name); + flag); } -const char *git_committer_info(int error_on_no_name) +const char *git_committer_info(int flag) { return fmt_ident(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"), getenv("GIT_COMMITTER_DATE"), - error_on_no_name); + flag); } diff --git a/refs.c b/refs.c index 3e6e98c5eb..759924d0c9 100644 --- a/refs.c +++ b/refs.c @@ -1094,7 +1094,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1, adjust_shared_perm(log_file); msglen = msg ? strlen(msg) : 0; - committer = git_committer_info(-1); + committer = git_committer_info(0); maxlen = strlen(committer) + msglen + 100; logrec = xmalloc(maxlen); len = sprintf(logrec, "%s %s %s\n", diff --git a/var.c b/var.c index 4127031910..0de0efa2aa 100644 --- a/var.c +++ b/var.c @@ -21,7 +21,7 @@ static void list_vars(void) { struct git_var *ptr; for(ptr = git_vars; ptr->read; ptr++) { - printf("%s=%s\n", ptr->name, ptr->read(0)); + printf("%s=%s\n", ptr->name, ptr->read(IDENT_WARN_ON_NO_NAME)); } } @@ -32,7 +32,7 @@ static const char *read_var(const char *var) val = NULL; for(ptr = git_vars; ptr->read; ptr++) { if (strcmp(var, ptr->name) == 0) { - val = ptr->read(1); + val = ptr->read(IDENT_ERROR_ON_NO_NAME); break; } } -- cgit v1.3 From bf82a15095ed374496c2e98b6b672aa8c8c4d034 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 10 Dec 2007 21:02:26 -0800 Subject: commit: do not add extra LF at the end of the summary. The scripted version relied on the nice "auto-strip the terminating LF" behaviour shell gives to "var=$(cmd)" construct, but we have to roll that ourselves. Signed-off-by: Junio C Hamano --- builtin-commit.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index b6b81d531d..9cb7589ac6 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -660,12 +660,16 @@ static void print_summary(const char *prefix, const unsigned char *sha1) rev.verbose_header = 1; rev.show_root_diff = 1; rev.commit_format = get_commit_format("format:%h: %s"); - rev.always_show_header = 1; + rev.always_show_header = 0; printf("Created %scommit ", initial_commit ? "initial " : ""); - log_tree_commit(&rev, commit); - printf("\n"); + if (!log_tree_commit(&rev, commit)) { + struct strbuf buf = STRBUF_INIT; + format_commit_message(commit, "%h: %s", &buf); + printf("%s\n", buf.buf); + strbuf_release(&buf); + } } int git_commit_config(const char *k, const char *v) -- cgit v1.3 From 37d07f8f9841a29cb53a1eda6acd3804c957f0e3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 12 Dec 2007 19:09:16 -0800 Subject: git-commit: squelch needless message during an empty merge When recording a merge that conflicted and ends up in no changes after manual resolution, commit callchain looked like this: cmd_commit() -> prepare_log_message() -> run_status() -> wt_status_print() This invocation of run_status() is asked to find out if there is a committable change, but it unconditionally gave instructions such as "use git-add" at the same time. When in merge, we do allow an empty change to be recorded, so after showing this message the code still went ahead and made a commit. This introduces "nowarn" parameter to run_status() to avoid these useless messages. If we are not allowed to create an empty commit, we already call run_status() again in the original codepath, and the message will be shown from that call anyway. Signed-off-by: Junio C Hamano --- builtin-commit.c | 9 +++++---- wt-status.c | 2 ++ wt-status.h | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 9cb7589ac6..ad9f9211b3 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -280,7 +280,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) return false_lock.filename; } -static int run_status(FILE *fp, const char *index_file, const char *prefix) +static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn) { struct wt_status s; @@ -296,6 +296,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix) s.untracked = untracked_files; s.index_file = index_file; s.fp = fp; + s.nowarn = nowarn; wt_status_print(&s); @@ -412,7 +413,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) saved_color_setting = wt_status_use_color; wt_status_use_color = 0; - commitable = run_status(fp, index_file, prefix); + commitable = run_status(fp, index_file, prefix, 1); wt_status_use_color = saved_color_setting; fclose(fp); @@ -606,7 +607,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) index_file = prepare_index(argc, argv, prefix); - commitable = run_status(stdout, index_file, prefix); + commitable = run_status(stdout, index_file, prefix, 0); rollback_index_files(); @@ -717,7 +718,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (!prepare_log_message(index_file, prefix) && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { - run_status(stdout, index_file, prefix); + run_status(stdout, index_file, prefix, 0); rollback_index_files(); unlink(commit_editmsg); return 1; diff --git a/wt-status.c b/wt-status.c index 51c1879691..c0c247243b 100644 --- a/wt-status.c +++ b/wt-status.c @@ -381,6 +381,8 @@ void wt_status_print(struct wt_status *s) if (!s->commitable) { if (s->amend) fprintf(s->fp, "# No changes\n"); + else if (s->nowarn) + ; /* nothing */ else if (s->workdir_dirty) printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n"); else if (s->workdir_untracked) diff --git a/wt-status.h b/wt-status.h index 63d50f2871..02afaa60ee 100644 --- a/wt-status.h +++ b/wt-status.h @@ -17,6 +17,7 @@ struct wt_status { int verbose; int amend; int untracked; + int nowarn; /* These are computed during processing of the individual sections */ int commitable; int workdir_dirty; -- cgit v1.3 From 1eb1e9eea480059d4fba171e74a4375b8191e3f3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Dec 2007 11:57:22 -0800 Subject: commit: allow --amend to reuse message from another commit After tentatively applying a patch from a contributor, you can get a replacement patch with corrected code and unusable commit log message. In such a case, this sequence ought to give you an editor based on the message in the earlier commit, to let you describe an incremental improvement: git reset --hard HEAD^ ;# discard the earlier one git am --- builtin-commit.c | 2 +- t/t7501-commit.sh | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index ad9f9211b3..518ebe0347 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -537,7 +537,7 @@ static int parse_and_validate_options(int argc, const char *argv[], die("Option -m cannot be combined with -c/-C/-F."); if (edit_message) use_message = edit_message; - if (amend) + if (amend && !use_message) use_message = "HEAD"; if (use_message) { unsigned char sha1[20]; diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 05aa97d6f3..d1a415a126 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -310,4 +310,21 @@ test_expect_success 'same tree (merge and amend merge)' ' ' +test_expect_success 'amend using the message from another commit' ' + + git reset --hard && + test_tick && + git commit --allow-empty -m "old commit" && + old=$(git rev-parse --verify HEAD) && + test_tick && + git commit --allow-empty -m "new commit" && + new=$(git rev-parse --verify HEAD) && + test_tick && + git commit --allow-empty --amend -C "$old" && + git show --pretty="format:%ad %s" "$old" >expected && + git show --pretty="format:%ad %s" HEAD >actual && + diff -u expected actual + +' + test_done -- cgit v1.3 From 1596456309315befb3fd0a985d50a70ed09493e4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 16 Dec 2007 15:03:58 -0800 Subject: builtin-commit: fix summary output. Because print_summary() forgot to call diff_setup_done() after futzing with diff output options, it failed to activate recursive diff, which resulted in an incorrect summary. Signed-off-by: Junio C Hamano --- builtin-commit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 518ebe0347..61770ef456 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -662,6 +662,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) rev.show_root_diff = 1; rev.commit_format = get_commit_format("format:%h: %s"); rev.always_show_header = 0; + diff_setup_done(&rev.diffopt); printf("Created %scommit ", initial_commit ? "initial " : ""); -- cgit v1.3 From 3eb2a15eb385749fbfe59b4e37fc754416275760 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 16 Dec 2007 15:05:39 -0800 Subject: builtin-commit: make summary output consistent with status This enables -B -M to the summary output after a commit is made so that it is in line with what is shown in git-status and commit log template. Signed-off-by: Junio C Hamano --- builtin-commit.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 61770ef456..0a9101324f 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -662,6 +662,9 @@ static void print_summary(const char *prefix, const unsigned char *sha1) rev.show_root_diff = 1; rev.commit_format = get_commit_format("format:%h: %s"); rev.always_show_header = 0; + rev.diffopt.detect_rename = 1; + rev.diffopt.rename_limit = 100; + rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); printf("Created %scommit ", initial_commit ? "initial " : ""); -- cgit v1.3 From fbcf1184026197128582369074201c490009b4eb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 19 Dec 2007 19:23:03 -0800 Subject: fix git commit --amend -m "new message" The prepare_log_message() function serves two purposes: - Prepares the commit log message template, to be given to the end user; - Return true if there is something committable; 7168624c3530d8c7ee32f930f8fb2ba302b9801f (Do not generate full commit log message if it is not going to be used) cheated to omit the former when we know the log message template is not going to be used. However, its replacement logic to see if there is something committable was botched. When amending, it should compare the index with the parent of the HEAD, not the current HEAD. Otherwise you cannot run --amend to fix only the message without changing the tree. Signed-off-by: Junio C Hamano --- builtin-commit.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 0a9101324f..96410de55d 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -375,6 +375,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) if (no_edit) { struct rev_info rev; unsigned char sha1[40]; + const char *parent = "HEAD"; fclose(fp); @@ -384,9 +385,12 @@ static int prepare_log_message(const char *index_file, const char *prefix) if (get_sha1("HEAD", sha1) != 0) return !!active_nr; + if (amend) + parent = "HEAD^1"; + init_revisions(&rev, ""); rev.abbrev = 0; - setup_revisions(0, NULL, &rev, "HEAD"); + 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 */); -- cgit v1.3 From d616a2396456fdb6679efa0c0bee301aeb606ca8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 22 Dec 2007 19:22:29 -0800 Subject: builtin-commit: fix amending of the initial commit When amending initial commit without editor, the command incorrectly barfed because the check to see if there is anything to commit referenced the non-existent HEAD^1. Signed-off-by: Junio C Hamano --- builtin-commit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 96410de55d..eebd4cf066 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -374,7 +374,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) if (no_edit) { struct rev_info rev; - unsigned char sha1[40]; + unsigned char sha1[20]; const char *parent = "HEAD"; fclose(fp); @@ -382,12 +382,12 @@ static int prepare_log_message(const char *index_file, const char *prefix) if (!active_nr && read_cache() < 0) die("Cannot read index"); - if (get_sha1("HEAD", sha1) != 0) - return !!active_nr; - if (amend) parent = "HEAD^1"; + if (get_sha1(parent, sha1)) + return !!active_nr; + init_revisions(&rev, ""); rev.abbrev = 0; setup_revisions(0, NULL, &rev, parent); -- cgit v1.3 From 4803466f62777fe3d0b33c8f999ec392f47a5b09 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 22 Dec 2007 19:25:37 -0800 Subject: builtin-commit: avoid double-negation in the code. The flag no_edit meant "we have got final message from the user and will not editing it any further", but there were quite a few places that needed to check !no_edit. Rename the variable to use_editor and reverse the logic everywhere. Signed-off-by: Junio C Hamano --- builtin-commit.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index eebd4cf066..1d544cbe35 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -48,7 +48,7 @@ static char *edit_message, *use_message; static int all, edit_flag, also, interactive, only, amend, signoff; static int quiet, verbose, untracked_files, no_verify, allow_empty; -static int no_edit, initial_commit, in_merge; +static int use_editor = 1, initial_commit, in_merge; const char *only_include_assumed; struct strbuf message; @@ -372,7 +372,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) strbuf_release(&sb); - if (no_edit) { + if (!use_editor) { struct rev_info rev; unsigned char sha1[20]; const char *parent = "HEAD"; @@ -398,7 +398,7 @@ static int prepare_log_message(const char *index_file, const char *prefix) return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); } - if (in_merge && !no_edit) + if (in_merge) fprintf(fp, "#\n" "# It looks like you may be committing a MERGE.\n" @@ -513,9 +513,9 @@ static int parse_and_validate_options(int argc, const char *argv[], argc = parse_options(argc, argv, builtin_commit_options, usage, 0); if (logfile || message.len || use_message) - no_edit = 1; + use_editor = 0; if (edit_flag) - no_edit = 0; + use_editor = 1; if (get_sha1("HEAD", head_sha1)) initial_commit = 1; @@ -796,7 +796,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) /* Get the commit message and validate it */ header_len = sb.len; - if (!no_edit) { + if (use_editor) { char index[PATH_MAX]; const char *env[2] = { index, NULL }; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); -- cgit v1.3 From 5f0657374344a5d8cf5ce5a9920a08c0be422194 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Sat, 22 Dec 2007 19:46:24 +0100 Subject: Allow selection of different cleanup modes for commit messages Although we traditionally stripped away excess blank lines, trailing whitespaces and lines that begin with "#" from the commit log message, sometimes the message just has to be the way user wants it. For instance, a commit message template can contain lines that begin with "#", the message must be kept as close to its original source as possible if you are converting from a foreign SCM, or maybe the message has a shell script including its comments for future reference. The cleanup modes are default, verbatim, whitespace and strip. The default mode depends on if the message is being edited and will either strip whitespace and comments (if editor active) or just strip the whitespace (for where the message is given explicitely). Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- Documentation/git-commit.txt | 12 +++++++- builtin-commit.c | 42 +++++++++++++++++++++++++--- t/t7502-commit.sh | 65 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 5 deletions(-) (limited to 'builtin-commit.c') diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 4261384158..96383b6543 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -11,7 +11,7 @@ SYNOPSIS 'git-commit' [-a | --interactive] [-s] [-v] [-u] [(-c | -C) | -F | -m | --amend] [--allow-empty] [--no-verify] [-e] [--author ] - [--] [[-i | -o ]...] + [--cleanup=] [--] [[-i | -o ]...] DESCRIPTION ----------- @@ -95,6 +95,16 @@ OPTIONS from making such a commit. This option bypasses the safety, and is primarily for use by foreign scm interface scripts. +--cleanup=:: + This option sets how the commit message is cleaned up. + The '' can be one of 'verbatim', 'whitespace', 'strip', + and 'default'. The 'default' mode will strip leading and + trailing empty lines and #commentary from the commit message + only if the message is to be edited. Otherwise only whitespace + removed. The 'verbatim' mode does not change message at all, + 'whitespace' removes just leading/trailing whitespace lines + and 'strip' removes both whitespace and commentary. + -e|--edit:: The message taken from file with `-F`, command line with `-m`, and from file with `-C` are usually used as the diff --git a/builtin-commit.c b/builtin-commit.c index 1d544cbe35..73f1e3576a 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -47,6 +47,19 @@ static char *logfile, *force_author, *template_file; static char *edit_message, *use_message; static int all, edit_flag, also, interactive, only, amend, signoff; static int quiet, verbose, untracked_files, no_verify, allow_empty; +/* + * The default commit message cleanup mode will remove the lines + * beginning with # (shell comments) and leading and trailing + * whitespaces (empty lines or containing only whitespaces) + * if editor is used, and only the whitespaces if the message + * is specified explicitly. + */ +static enum { + CLEANUP_SPACE, + CLEANUP_NONE, + CLEANUP_ALL, +} cleanup_mode; +static char *cleanup_arg; static int use_editor = 1, initial_commit, in_merge; const char *only_include_assumed; @@ -88,6 +101,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"), OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), + OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), OPT_END() }; @@ -346,7 +360,8 @@ static int prepare_log_message(const char *index_file, const char *prefix) if (fp == NULL) die("could not open %s", git_path(commit_editmsg)); - stripspace(&sb, 0); + if (cleanup_mode != CLEANUP_NONE) + stripspace(&sb, 0); if (signoff) { struct strbuf sob; @@ -411,7 +426,12 @@ static int prepare_log_message(const char *index_file, const char *prefix) fprintf(fp, "\n" "# Please enter the commit message for your changes.\n" - "# (Comment lines starting with '#' will not be included)\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); @@ -435,10 +455,13 @@ static int message_is_empty(struct strbuf *sb, int start) const char *nl; int eol, i; + if (cleanup_mode == CLEANUP_NONE && sb->len) + return 0; + /* See if the template is just a prefix of the message. */ strbuf_init(&tmpl, 0); if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) { - stripspace(&tmpl, 1); + stripspace(&tmpl, cleanup_mode == CLEANUP_ALL); if (start + tmpl.len <= sb->len && memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0) start += tmpl.len; @@ -591,6 +614,16 @@ static int parse_and_validate_options(int argc, const char *argv[], only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths..."; also = 0; } + if (!cleanup_arg || !strcmp(cleanup_arg, "default")) + cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE; + else if (!strcmp(cleanup_arg, "verbatim")) + cleanup_mode = CLEANUP_NONE; + else if (!strcmp(cleanup_arg, "whitespace")) + cleanup_mode = CLEANUP_SPACE; + else if (!strcmp(cleanup_arg, "strip")) + cleanup_mode = CLEANUP_ALL; + else + die("Invalid cleanup mode %s", cleanup_arg); if (all && argc > 0) die("Paths with -a does not make sense."); @@ -817,7 +850,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) if (p != NULL) strbuf_setlen(&sb, p - sb.buf + 1); - stripspace(&sb, 1); + if (cleanup_mode != CLEANUP_NONE) + stripspace(&sb, cleanup_mode == CLEANUP_ALL); if (sb.len < header_len || message_is_empty(&sb, header_len)) { rollback_index_files(); die("no commit message? aborting commit."); diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 21ac785e3d..aaf497e6a5 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -89,4 +89,69 @@ test_expect_success 'verbose' ' ' +test_expect_success 'cleanup commit messages (verbatim,-t)' ' + + echo >>negative && + { echo;echo "# text";echo; } >expect && + git commit --cleanup=verbatim -t expect -a && + git cat-file -p HEAD |sed -e "1,/^\$/d" |head -n 3 >actual && + diff -u expect actual + +' + +test_expect_success 'cleanup commit messages (verbatim,-F)' ' + + echo >>negative && + git commit --cleanup=verbatim -F expect -a && + git cat-file -p HEAD |sed -e "1,/^\$/d">actual && + diff -u expect actual + +' + +test_expect_success 'cleanup commit messages (verbatim,-m)' ' + + echo >>negative && + git commit --cleanup=verbatim -m "$(cat expect)" -a && + git cat-file -p HEAD |sed -e "1,/^\$/d">actual && + diff -u expect actual + +' + +test_expect_success 'cleanup commit messages (whitespace,-F)' ' + + echo >>negative && + { echo;echo "# text";echo; } >text && + echo "# text" >expect && + git commit --cleanup=whitespace -F text -a && + git cat-file -p HEAD |sed -e "1,/^\$/d">actual && + diff -u expect actual + +' + +test_expect_success 'cleanup commit messages (strip,-F)' ' + + echo >>negative && + { echo;echo "# text";echo sample;echo; } >text && + echo sample >expect && + git commit --cleanup=strip -F text -a && + git cat-file -p HEAD |sed -e "1,/^\$/d">actual && + diff -u expect actual + +' + +echo "sample + +# Please enter the commit message for your changes. +# (Comment lines starting with '#' will not be included)" >expect + +test_expect_success 'cleanup commit messages (strip,-F,-e)' ' + + echo >>negative && + { echo;echo sample;echo; } >text && + git commit -e -F text -a && + head -n 4 .git/COMMIT_EDITMSG >actual && + diff -u expect actual + +' + test_done -- cgit v1.3 From fa9dcf80e1048ea996349891a885ac325019fcac Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 13 Jan 2008 00:30:56 -0800 Subject: Fix performance regression for partial commits When running "git commit paths" to create a partial commit, we used to carefully build the temporary index so that we do not lose the cached stat information. The rewrite of the command in C lost it by carelessly using read_tree(). This resurrects the earlier behaviour to keep the cached stat information as much as possible by using one-tree merge logic. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-commit.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 73f1e3576a..6d2ca808b5 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -21,6 +21,7 @@ #include "utf8.h" #include "parse-options.h" #include "path-list.h" +#include "unpack-trees.h" static const char * const builtin_commit_usage[] = { "git-commit [options] [--] ...", @@ -177,10 +178,34 @@ static void add_remove_files(struct path_list *list) } } +static void create_base_index(void) +{ + struct tree *tree; + struct unpack_trees_options opts; + struct tree_desc t; + + if (initial_commit) { + discard_cache(); + return; + } + + memset(&opts, 0, sizeof(opts)); + opts.head_idx = 1; + opts.index_only = 1; + opts.merge = 1; + + opts.fn = oneway_merge; + tree = parse_tree_indirect(head_sha1); + if (!tree) + die("failed to unpack HEAD tree object"); + parse_tree(tree); + init_tree_desc(&t, tree->buffer, tree->size); + unpack_trees(1, &t, &opts); +} + static char *prepare_index(int argc, const char **argv, const char *prefix) { int fd; - struct tree *tree; struct path_list partial; const char **pathspec = NULL; @@ -278,14 +303,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) fd = hold_lock_file_for_update(&false_lock, git_path("next-index-%d", getpid()), 1); - discard_cache(); - if (!initial_commit) { - tree = parse_tree_indirect(head_sha1); - if (!tree) - die("failed to unpack HEAD tree object"); - if (read_tree(tree, 0, NULL)) - die("failed to read HEAD tree object"); - } + + create_base_index(); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); -- cgit v1.3 From 16335fdd7ace78a8285ba25fd7a81177a48e7c9b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 13 Jan 2008 02:38:46 -0800 Subject: builtin-commit.c: remove useless check added by faulty cut and paste 2888605c649ccd423232161186d72c0e6c458a48 (builtin-commit: fix partial-commit support) mindlessly cut and pasted from builtin-ls-files.c, and included a part that was meant to exclude redundant path after "ls-files --with-tree" overlayed the HEAD commit on top of the index. This logic does not apply to what git-commit does and should not have been copied, even though it would not hurt. Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 6d2ca808b5..265ba6bcd4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -156,8 +156,6 @@ static int list_paths(struct path_list *list, const char *with_tree, for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - if (ce->ce_flags & htons(CE_UPDATE)) - continue; if (!pathspec_match(pattern, m, ce->name, 0)) continue; path_list_insert(ce->name, list); -- cgit v1.3 From e87e22d0f22eb262a90e76197465d6cfd9707ea1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 14 Jan 2008 13:54:24 -0800 Subject: Revert "builtin-commit.c: remove useless check added by faulty cut and paste" This reverts commit 16335fdd7ace78a8285ba25fd7a81177a48e7c9b. We are calling overlay_tree_on_cache() which does use CE_UPDATE flag to mark duplicated entries, which is the same as the codepath in git-ls-files with its --with-tree option. Because the pathname ce->name is given to path_list_insert() which does not allow duplicates, there is no breakage either way from the correctness point of view in this codepath, unlike the one in ls-files. But avoiding unnecessary processing with a single bit check is certainly better. --- builtin-commit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 265ba6bcd4..6d2ca808b5 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -156,6 +156,8 @@ static int list_paths(struct path_list *list, const char *with_tree, for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; + if (ce->ce_flags & htons(CE_UPDATE)) + continue; if (!pathspec_match(pattern, m, ce->name, 0)) continue; path_list_insert(ce->name, list); -- cgit v1.3 From 4439751dcbc3ba2fccae70626654f7950a7b298c Mon Sep 17 00:00:00 2001 From: Kristian Høgsberg Date: Tue, 15 Jan 2008 15:00:02 -0500 Subject: git-commit: fix double close(2) that can close a wrong file descriptor The codepath to prepare index files for the temporary and next index file was closing file descriptor it obtained from the lockfile API by hand, without letting the API know that the fd should not be doubly closed. This is not usually a problem (except it may get EBADFD) but if we opened another fd for an entirely unrelated purpose (say, an fd used to mmap a packfile) between the time we close the fd to the index file and the time we commit or rollback the lockfile (causing it to also try closing the recorded fd), the lockfile API will close an incorrect file descriptor that is still used for an entirely unrelated purpose. There's four close(fd) calls in prepare_index() and they're all incorrect. The open fd's are cleaned up in rollback_index_files() and shouldn't be closed manually. The patch below gets rid of the extra close() calls and should fix the problem. Signed-off-by: Junio C Hamano --- builtin-commit.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 6d2ca808b5..16345e9b93 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -237,7 +237,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) int fd = hold_locked_index(&index_lock, 1); add_files_to_cache(0, also ? prefix : NULL, pathspec); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr) || close(fd)) + if (write_cache(fd, active_cache, active_nr)) die("unable to write new_index file"); commit_style = COMMIT_NORMAL; return index_lock.filename; @@ -256,7 +256,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) fd = hold_locked_index(&index_lock, 1); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || - close(fd) || commit_locked_index(&index_lock)) + commit_locked_index(&index_lock)) die("unable to write new_index file"); commit_style = COMMIT_AS_IS; return get_index_file(); @@ -298,7 +298,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) fd = hold_locked_index(&index_lock, 1); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr) || close(fd)) + if (write_cache(fd, active_cache, active_nr)) die("unable to write new_index file"); fd = hold_lock_file_for_update(&false_lock, @@ -308,7 +308,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr) || close(fd)) + if (write_cache(fd, active_cache, active_nr)) die("unable to write temporary index file"); return false_lock.filename; } -- cgit v1.3 From 7c3fd25dcf2a23ed43bae2ba23a46edab4644a9f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 15 Jan 2008 16:12:33 -0800 Subject: Make builtin-commit.c more careful about parenthood When creating the commit object, be a whole lot more careful about making sure that the parent lines really are valid parent lines. Check things like MERGE_HEAD having proper SHA1 lines in it, and double-check that all the parents exist and are actually commits. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-commit.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 16345e9b93..49541c0583 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -756,6 +756,17 @@ static const char commit_utf8_warn[] = "You may want to amend it after fixing the message, or set the config\n" "variable i18n.commitencoding to the encoding your project uses.\n"; +static void add_parent(struct strbuf *sb, const unsigned char *sha1) +{ + struct object *obj = parse_object(sha1); + const char *parent = sha1_to_hex(sha1); + if (!obj) + die("Unable to find commit parent %s", parent); + if (obj->type != OBJ_COMMIT) + die("Parent %s isn't a proper commit", parent); + strbuf_addf(sb, "parent %s\n", parent); +} + int cmd_commit(int argc, const char **argv, const char *prefix) { int header_len; @@ -818,21 +829,24 @@ int cmd_commit(int argc, const char **argv, const char *prefix) die("could not parse HEAD commit"); for (c = commit->parents; c; c = c->next) - strbuf_addf(&sb, "parent %s\n", - sha1_to_hex(c->item->object.sha1)); + add_parent(&sb, c->item->object.sha1); } else if (in_merge) { struct strbuf m; FILE *fp; reflog_msg = "commit (merge)"; - strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1)); + add_parent(&sb, head_sha1); strbuf_init(&m, 0); fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die("could not open %s for reading: %s", git_path("MERGE_HEAD"), strerror(errno)); - while (strbuf_getline(&m, fp, '\n') != EOF) - strbuf_addf(&sb, "parent %s\n", m.buf); + while (strbuf_getline(&m, fp, '\n') != EOF) { + unsigned char sha1[20]; + if (get_sha1_hex(m.buf, sha1) < 0) + die("Corrupt MERGE_HEAD file (%s)", m.buf); + add_parent(&sb, sha1); + } fclose(fp); strbuf_release(&m); } else { -- cgit v1.3 From 4ed7cd3ab07f7c721daf4241fe1dac306fefd1fb Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Wed, 16 Jan 2008 13:12:46 -0600 Subject: Improve use of lockfile API Remove remaining double close(2)'s. i.e. close() before commit_locked_index() or commit_lock_file(). Signed-off-by: Junio C Hamano --- builtin-add.c | 2 +- builtin-apply.c | 2 +- builtin-checkout-index.c | 4 ++-- builtin-commit.c | 9 ++++++--- builtin-diff.c | 2 +- builtin-fetch-pack.c | 1 - builtin-mv.c | 1 - builtin-pack-refs.c | 6 ++++++ builtin-read-tree.c | 2 +- builtin-rerere.c | 4 ++-- builtin-reset.c | 1 - builtin-revert.c | 4 ++-- builtin-rm.c | 2 +- builtin-update-index.c | 2 +- builtin-write-tree.c | 9 +++------ bundle.c | 14 ++++++++++---- config.c | 8 ++------ fast-import.c | 12 ++++++++++-- merge-recursive.c | 2 +- refs.c | 12 ++++-------- 20 files changed, 54 insertions(+), 45 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-add.c b/builtin-add.c index 5c29cc2f3f..4a91e3eb11 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -259,7 +259,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) finish: if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(&lock_file)) + commit_locked_index(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-apply.c b/builtin-apply.c index d57bb6e070..15432b6782 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2921,7 +2921,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) if (update_index) { if (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(&lock_file)) + commit_locked_index(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 70d619da8d..7e42024c67 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -246,8 +246,8 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) * want to update cache. */ if (state.refresh_cache) { - close(newfd); newfd = -1; rollback_lock_file(&lock_file); + newfd = -1; } state.refresh_cache = 0; } @@ -297,7 +297,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) if (0 <= newfd && (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(&lock_file))) + commit_locked_index(&lock_file))) die("Unable to write new index file"); return 0; } diff --git a/builtin-commit.c b/builtin-commit.c index 49541c0583..02279360f7 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -237,7 +237,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) int fd = hold_locked_index(&index_lock, 1); add_files_to_cache(0, also ? prefix : NULL, pathspec); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr)) + if (write_cache(fd, active_cache, active_nr) || + close_lock_file(&index_lock)) die("unable to write new_index file"); commit_style = COMMIT_NORMAL; return index_lock.filename; @@ -298,7 +299,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) fd = hold_locked_index(&index_lock, 1); add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr)) + if (write_cache(fd, active_cache, active_nr) || + close_lock_file(&index_lock)) die("unable to write new_index file"); fd = hold_lock_file_for_update(&false_lock, @@ -308,7 +310,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_cache(fd, active_cache, active_nr)) + if (write_cache(fd, active_cache, active_nr) || + close_lock_file(&false_lock)) die("unable to write temporary index file"); return false_lock.filename; } diff --git a/builtin-diff.c b/builtin-diff.c index 29365a0b17..8d7a5697f2 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -190,7 +190,7 @@ static void refresh_index_quietly(void) refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED); if (active_cache_changed && - !write_cache(fd, active_cache, active_nr) && !close(fd)) + !write_cache(fd, active_cache, active_nr)) commit_locked_index(lock_file); rollback_lock_file(lock_file); diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 807fa93b53..e68e01592d 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -783,7 +783,6 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, unlink(shallow); rollback_lock_file(&lock); } else { - close(fd); commit_lock_file(&lock); } } diff --git a/builtin-mv.c b/builtin-mv.c index a3f9ad1744..990e21355d 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -264,7 +264,6 @@ int cmd_mv(int argc, const char **argv, const char *prefix) if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c index 1923fb1914..1aaa76dd1f 100644 --- a/builtin-pack-refs.c +++ b/builtin-pack-refs.c @@ -108,6 +108,12 @@ static int pack_refs(unsigned int flags) die("failed to write ref-pack file"); if (fflush(cbdata.refs_file) || fsync(fd) || fclose(cbdata.refs_file)) die("failed to write ref-pack file (%s)", strerror(errno)); + /* + * Since the lock file was fdopen()'ed and then fclose()'ed above, + * assign -1 to the lock file descriptor so that commit_lock_file() + * won't try to close() it. + */ + packed.fd = -1; if (commit_lock_file(&packed) < 0) die("unable to overwrite old ref-pack file (%s)", strerror(errno)); if (cbdata.flags & PACK_REFS_PRUNE) diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 43cd56a3b5..c0ea0342b7 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -283,7 +283,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) } if (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(&lock_file)) + commit_locked_index(&lock_file)) die("unable to write new index file"); return 0; } diff --git a/builtin-rerere.c b/builtin-rerere.c index 37e6248138..a9e3ebc137 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -61,9 +61,9 @@ static int write_rr(struct path_list *rr, int out_fd) write_in_full(out_fd, path, length) != length) die("unable to write rerere record"); } - if (close(out_fd) != 0) + if (commit_lock_file(&write_lock) != 0) die("unable to write rerere record"); - return commit_lock_file(&write_lock); + return 0; } static int handle_file(const char *path, diff --git a/builtin-reset.c b/builtin-reset.c index 10dba60c39..7ee811f0b8 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -108,7 +108,6 @@ static int update_index_refresh(int fd, struct lock_file *index_lock) return error("Could not read index"); result = refresh_cache(0) ? 1 : 0; if (write_cache(fd, active_cache, active_nr) || - close(fd) || commit_locked_index(index_lock)) return error ("Could not refresh index"); return result; diff --git a/builtin-revert.c b/builtin-revert.c index 4bf8eb2f58..358af53747 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -371,13 +371,13 @@ static int revert_or_cherry_pick(int argc, const char **argv) i++; } } - if (close(msg_fd) || commit_lock_file(&msg_file) < 0) + if (commit_lock_file(&msg_file) < 0) die ("Error wrapping up %s", defmsg); fprintf(stderr, "Automatic %s failed.%s\n", me, help_msg(commit->object.sha1)); exit(1); } - if (close(msg_fd) || commit_lock_file(&msg_file) < 0) + if (commit_lock_file(&msg_file) < 0) die ("Error wrapping up %s", defmsg); fprintf(stderr, "Finished one %s.\n", me); diff --git a/builtin-rm.c b/builtin-rm.c index a3d25e6a57..c0a8bb6cf5 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -250,7 +250,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(&lock_file)) + commit_locked_index(&lock_file)) die("Unable to write new index file"); } diff --git a/builtin-update-index.c b/builtin-update-index.c index e1a938d897..c3a14c74ed 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -738,7 +738,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) get_index_file(), strerror(lock_error)); } if (write_cache(newfd, active_cache, active_nr) || - close(newfd) || commit_locked_index(lock_file)) + commit_locked_index(lock_file)) die("Unable to write new index file"); } diff --git a/builtin-write-tree.c b/builtin-write-tree.c index b89d02efec..d16b9ed009 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -35,11 +35,9 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix) missing_ok, 0) < 0) die("git-write-tree: error building trees"); if (0 <= newfd) { - if (!write_cache(newfd, active_cache, active_nr) - && !close(newfd)) { - commit_lock_file(lock_file); + if (!write_cache(newfd, active_cache, active_nr) && + !commit_lock_file(lock_file)) newfd = -1; - } } /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller @@ -60,8 +58,7 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix) hashcpy(sha1, active_cache_tree->sha1); if (0 <= newfd) - close(newfd); - rollback_lock_file(lock_file); + rollback_lock_file(lock_file); return 0; } diff --git a/bundle.c b/bundle.c index 316aa7420d..5c95eca07d 100644 --- a/bundle.c +++ b/bundle.c @@ -317,6 +317,14 @@ int create_bundle(struct bundle_header *header, const char *path, rls.git_cmd = 1; if (start_command(&rls)) return error("Could not spawn pack-objects"); + + /* + * start_command closed bundle_fd if it was > 1 + * so set the lock fd to -1 so commit_lock_file() + * won't fail trying to close it. + */ + lock.fd = -1; + for (i = 0; i < revs.pending.nr; i++) { struct object *object = revs.pending.objects[i].item; if (object->flags & UNINTERESTING) @@ -326,10 +334,8 @@ int create_bundle(struct bundle_header *header, const char *path, } if (finish_command(&rls)) return error ("pack-objects died"); - close(bundle_fd); - if (!bundle_to_stdout) - commit_lock_file(&lock); - return 0; + + return bundle_to_stdout ? close(bundle_fd) : commit_lock_file(&lock); } int unbundle(struct bundle_header *header, int bundle_fd) diff --git a/config.c b/config.c index 857deb6c85..526a3f4294 100644 --- a/config.c +++ b/config.c @@ -955,14 +955,12 @@ int git_config_set_multivar(const char* key, const char* value, munmap(contents, contents_sz); } - if (close(fd) || commit_lock_file(lock) < 0) { + if (commit_lock_file(lock) < 0) { fprintf(stderr, "Cannot commit config file!\n"); ret = 4; goto out_free; } - /* fd is closed, so don't try to close it below. */ - fd = -1; /* * lock is committed, so don't try to roll it back below. * NOTE: Since lockfile.c keeps a linked list of all created @@ -973,8 +971,6 @@ int git_config_set_multivar(const char* key, const char* value, ret = 0; out_free: - if (0 <= fd) - close(fd); if (lock) rollback_lock_file(lock); free(config_filename); @@ -1072,7 +1068,7 @@ int git_config_rename_section(const char *old_name, const char *new_name) } fclose(config_file); unlock_and_out: - if (close(out_fd) || commit_lock_file(lock) < 0) + if (commit_lock_file(lock) < 0) ret = error("Cannot commit config file!"); out: free(config_filename); diff --git a/fast-import.c b/fast-import.c index 82e9161339..3609c24288 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1546,10 +1546,18 @@ static void dump_marks(void) } dump_marks_helper(f, 0, marks); - fclose(f); - if (commit_lock_file(&mark_lock)) + if (ferror(f) || fclose(f)) failure |= error("Unable to write marks file %s: %s", mark_file, strerror(errno)); + /* + * Since the lock file was fdopen()'ed and then fclose()'ed above, + * assign -1 to the lock file descriptor so that commit_lock_file() + * won't try to close() it. + */ + mark_lock.fd = -1; + if (commit_lock_file(&mark_lock)) + failure |= error("Unable to write commit file %s: %s", + mark_file, strerror(errno)); } static int read_next_command(void) diff --git a/merge-recursive.c b/merge-recursive.c index b34177d20f..c292a77a81 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -1753,7 +1753,7 @@ int main(int argc, char *argv[]) if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || - close(index_fd) || commit_locked_index(lock))) + commit_locked_index(lock))) die ("unable to write %s", get_index_file()); return clean ? 0: 1; diff --git a/refs.c b/refs.c index c3ffe0393b..8a42d39fd7 100644 --- a/refs.c +++ b/refs.c @@ -864,7 +864,6 @@ static int repack_without_ref(const char *refname) die("too long a refname '%s'", list->name); write_or_die(fd, line, len); } - close(fd); return commit_lock_file(&packlock); } @@ -1021,12 +1020,9 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) void unlock_ref(struct ref_lock *lock) { - if (lock->lock_fd >= 0) { - close(lock->lock_fd); - /* Do not free lock->lk -- atexit() still looks at them */ - if (lock->lk) - rollback_lock_file(lock->lk); - } + /* Do not free lock->lk -- atexit() still looks at them */ + if (lock->lk) + rollback_lock_file(lock->lk); free(lock->ref_name); free(lock->orig_ref_name); free(lock); @@ -1151,7 +1147,7 @@ int write_ref_sha1(struct ref_lock *lock, } if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 || write_in_full(lock->lock_fd, &term, 1) != 1 - || close(lock->lock_fd) < 0) { + || close_lock_file(lock->lk) < 0) { error("Couldn't write %s", lock->lk->filename); unlock_ref(lock); return -1; -- cgit v1.3 From 7a51ed66f653c248993b3c4a61932e47933d835e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 14 Jan 2008 16:03:17 -0800 Subject: Make on-disk index representation separate from in-core one This converts the index explicitly on read and write to its on-disk format, allowing the in-core format to contain more flags, and be simpler. In particular, the in-core format is now host-endian (as opposed to the on-disk one that is network endian in order to be able to be shared across machines) and as a result we can dispense with all the htonl/ntohl on accesses to the cache_entry fields. This will make it easier to make use of various temporary flags that do not exist in the on-disk format. Signed-off-by: Linus Torvalds --- builtin-apply.c | 10 +-- builtin-blame.c | 2 +- builtin-commit.c | 2 +- builtin-fsck.c | 2 +- builtin-grep.c | 4 +- builtin-ls-files.c | 10 +-- builtin-read-tree.c | 3 +- builtin-rerere.c | 4 +- builtin-update-index.c | 18 ++--- cache-tree.c | 4 +- cache.h | 46 ++++++++---- diff-lib.c | 32 ++++---- dir.c | 2 +- entry.c | 6 +- merge-index.c | 2 +- merge-recursive.c | 2 +- reachable.c | 2 +- read-cache.c | 200 +++++++++++++++++++++++++++++-------------------- sha1_name.c | 2 +- tree.c | 4 +- unpack-trees.c | 29 ++++--- 21 files changed, 217 insertions(+), 169 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-apply.c b/builtin-apply.c index 15432b6782..30d86f2197 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1946,7 +1946,7 @@ static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf) if (!ce) return 0; - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { strbuf_grow(buf, 100); strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1)); } else { @@ -2023,7 +2023,7 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists) static int verify_index_match(struct cache_entry *ce, struct stat *st) { - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { if (!S_ISDIR(st->st_mode)) return -1; return 0; @@ -2082,12 +2082,12 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) return error("%s: does not match index", old_name); if (cached) - st_mode = ntohl(ce->ce_mode); + st_mode = ce->ce_mode; } else if (stat_ret < 0) return error("%s: %s", old_name, strerror(errno)); if (!cached) - st_mode = ntohl(ce_mode_from_stat(ce, st.st_mode)); + st_mode = ce_mode_from_stat(ce, st.st_mode); if (patch->is_new < 0) patch->is_new = 0; @@ -2388,7 +2388,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned ce = xcalloc(1, ce_size); memcpy(ce->name, path, namelen); ce->ce_mode = create_ce_mode(mode); - ce->ce_flags = htons(namelen); + ce->ce_flags = namelen; if (S_ISGITLINK(mode)) { const char *s = buf; diff --git a/builtin-blame.c b/builtin-blame.c index 9b4c02e87f..c7e68874e7 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2092,7 +2092,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con if (!mode) { int pos = cache_name_pos(path, len); if (0 <= pos) - mode = ntohl(active_cache[pos]->ce_mode); + mode = active_cache[pos]->ce_mode; else /* Let's not bother reading from HEAD tree */ mode = S_IFREG | 0644; diff --git a/builtin-commit.c b/builtin-commit.c index 02279360f7..c63ff826fc 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -156,7 +156,7 @@ static int list_paths(struct path_list *list, const char *with_tree, for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - if (ce->ce_flags & htons(CE_UPDATE)) + if (ce->ce_flags & CE_UPDATE) continue; if (!pathspec_match(pattern, m, ce->name, 0)) continue; diff --git a/builtin-fsck.c b/builtin-fsck.c index 2a6e94deaf..6fc9525e04 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -765,7 +765,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) struct blob *blob; struct object *obj; - mode = ntohl(active_cache[i]->ce_mode); + mode = active_cache[i]->ce_mode; if (S_ISGITLINK(mode)) continue; blob = lookup_blob(active_cache[i]->sha1); diff --git a/builtin-grep.c b/builtin-grep.c index 0d6cc7361f..9180b39e3f 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -331,7 +331,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached) struct cache_entry *ce = active_cache[i]; char *name; int kept; - if (!S_ISREG(ntohl(ce->ce_mode))) + if (!S_ISREG(ce->ce_mode)) continue; if (!pathspec_matches(paths, ce->name)) continue; @@ -387,7 +387,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached) for (nr = 0; nr < active_nr; nr++) { struct cache_entry *ce = active_cache[nr]; - if (!S_ISREG(ntohl(ce->ce_mode))) + if (!S_ISREG(ce->ce_mode)) continue; if (!pathspec_matches(paths, ce->name)) continue; diff --git a/builtin-ls-files.c b/builtin-ls-files.c index 0f0ab2da16..d56e33e251 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -189,7 +189,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) return; if (tag && *tag && show_valid_bit && - (ce->ce_flags & htons(CE_VALID))) { + (ce->ce_flags & CE_VALID)) { static char alttag[4]; memcpy(alttag, tag, 3); if (isalpha(tag[0])) @@ -210,7 +210,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) } else { printf("%s%06o %s %d\t", tag, - ntohl(ce->ce_mode), + ce->ce_mode, abbrev ? find_unique_abbrev(ce->sha1,abbrev) : sha1_to_hex(ce->sha1), ce_stage(ce)); @@ -242,7 +242,7 @@ static void show_files(struct dir_struct *dir, const char *prefix) continue; if (show_unmerged && !ce_stage(ce)) continue; - if (ce->ce_flags & htons(CE_UPDATE)) + if (ce->ce_flags & CE_UPDATE) continue; show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce); } @@ -350,7 +350,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - ce->ce_flags |= htons(CE_STAGEMASK); + ce->ce_flags |= CE_STAGEMASK; } if (prefix) { @@ -379,7 +379,7 @@ void overlay_tree_on_cache(const char *tree_name, const char *prefix) */ if (last_stage0 && !strcmp(last_stage0->name, ce->name)) - ce->ce_flags |= htons(CE_UPDATE); + ce->ce_flags |= CE_UPDATE; } } } diff --git a/builtin-read-tree.c b/builtin-read-tree.c index c0ea0342b7..5785401753 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -45,8 +45,7 @@ static int read_cache_unmerged(void) continue; cache_tree_invalidate_path(active_cache_tree, ce->name); last = ce; - ce->ce_mode = 0; - ce->ce_flags &= ~htons(CE_STAGEMASK); + ce->ce_flags |= CE_REMOVE; } *dst++ = ce; } diff --git a/builtin-rerere.c b/builtin-rerere.c index a9e3ebc137..b0c17bde87 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -149,8 +149,8 @@ static int find_conflict(struct path_list *conflict) if (ce_stage(e2) == 2 && ce_stage(e3) == 3 && ce_same_name(e2, e3) && - S_ISREG(ntohl(e2->ce_mode)) && - S_ISREG(ntohl(e3->ce_mode))) { + S_ISREG(e2->ce_mode) && + S_ISREG(e3->ce_mode)) { path_list_insert((const char *)e2->name, conflict); i++; /* skip over both #2 and #3 */ } diff --git a/builtin-update-index.c b/builtin-update-index.c index c3a14c74ed..a8795d3d5f 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -47,10 +47,10 @@ static int mark_valid(const char *path) if (0 <= pos) { switch (mark_valid_only) { case MARK_VALID: - active_cache[pos]->ce_flags |= htons(CE_VALID); + active_cache[pos]->ce_flags |= CE_VALID; break; case UNMARK_VALID: - active_cache[pos]->ce_flags &= ~htons(CE_VALID); + active_cache[pos]->ce_flags &= ~CE_VALID; break; } cache_tree_invalidate_path(active_cache_tree, path); @@ -95,7 +95,7 @@ static int add_one_path(struct cache_entry *old, const char *path, int len, stru size = cache_entry_size(len); ce = xcalloc(1, size); memcpy(ce->name, path, len); - ce->ce_flags = htons(len); + ce->ce_flags = len; fill_stat_cache_info(ce, st); ce->ce_mode = ce_mode_from_stat(old, st->st_mode); @@ -139,7 +139,7 @@ static int process_directory(const char *path, int len, struct stat *st) /* Exact match: file or existing gitlink */ if (pos >= 0) { struct cache_entry *ce = active_cache[pos]; - if (S_ISGITLINK(ntohl(ce->ce_mode))) { + if (S_ISGITLINK(ce->ce_mode)) { /* Do nothing to the index if there is no HEAD! */ if (resolve_gitlink_ref(path, "HEAD", sha1) < 0) @@ -183,7 +183,7 @@ static int process_file(const char *path, int len, struct stat *st) int pos = cache_name_pos(path, len); struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos]; - if (ce && S_ISGITLINK(ntohl(ce->ce_mode))) + if (ce && S_ISGITLINK(ce->ce_mode)) return error("%s is already a gitlink, not replacing", path); return add_one_path(ce, path, len, st); @@ -226,7 +226,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, ce->ce_flags = create_ce_flags(len, stage); ce->ce_mode = create_ce_mode(mode); if (assume_unchanged) - ce->ce_flags |= htons(CE_VALID); + ce->ce_flags |= CE_VALID; option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; if (add_cache_entry(ce, option)) @@ -246,14 +246,14 @@ static void chmod_path(int flip, const char *path) if (pos < 0) goto fail; ce = active_cache[pos]; - mode = ntohl(ce->ce_mode); + mode = ce->ce_mode; if (!S_ISREG(mode)) goto fail; switch (flip) { case '+': - ce->ce_mode |= htonl(0111); break; + ce->ce_mode |= 0111; break; case '-': - ce->ce_mode &= htonl(~0111); break; + ce->ce_mode &= ~0111; break; default: goto fail; } diff --git a/cache-tree.c b/cache-tree.c index 50b35264fd..bfc95d2dc9 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -320,13 +320,13 @@ static int update_one(struct cache_tree *it, } else { sha1 = ce->sha1; - mode = ntohl(ce->ce_mode); + mode = ce->ce_mode; entlen = pathlen - baselen; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) return error("invalid object %s", sha1_to_hex(sha1)); - if (!ce->ce_mode) + if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ strbuf_grow(&buffer, entlen + 100); diff --git a/cache.h b/cache.h index 549f4bbac7..4a054c5402 100644 --- a/cache.h +++ b/cache.h @@ -94,48 +94,66 @@ struct cache_time { * We save the fields in big-endian order to allow using the * index file over NFS transparently. */ +struct ondisk_cache_entry { + struct cache_time ctime; + struct cache_time mtime; + unsigned int dev; + unsigned int ino; + unsigned int mode; + unsigned int uid; + unsigned int gid; + unsigned int size; + unsigned char sha1[20]; + unsigned short flags; + char name[FLEX_ARRAY]; /* more */ +}; + struct cache_entry { - struct cache_time ce_ctime; - struct cache_time ce_mtime; + unsigned int ce_ctime; + unsigned int ce_mtime; unsigned int ce_dev; unsigned int ce_ino; unsigned int ce_mode; unsigned int ce_uid; unsigned int ce_gid; unsigned int ce_size; + unsigned int ce_flags; unsigned char sha1[20]; - unsigned short ce_flags; char name[FLEX_ARRAY]; /* more */ }; #define CE_NAMEMASK (0x0fff) #define CE_STAGEMASK (0x3000) -#define CE_UPDATE (0x4000) #define CE_VALID (0x8000) #define CE_STAGESHIFT 12 -#define create_ce_flags(len, stage) htons((len) | ((stage) << CE_STAGESHIFT)) -#define ce_namelen(ce) (CE_NAMEMASK & ntohs((ce)->ce_flags)) +/* In-memory only */ +#define CE_UPDATE (0x10000) +#define CE_REMOVE (0x20000) + +#define create_ce_flags(len, stage) ((len) | ((stage) << CE_STAGESHIFT)) +#define ce_namelen(ce) (CE_NAMEMASK & (ce)->ce_flags) #define ce_size(ce) cache_entry_size(ce_namelen(ce)) -#define ce_stage(ce) ((CE_STAGEMASK & ntohs((ce)->ce_flags)) >> CE_STAGESHIFT) +#define ondisk_ce_size(ce) ondisk_cache_entry_size(ce_namelen(ce)) +#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT) #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) static inline unsigned int create_ce_mode(unsigned int mode) { if (S_ISLNK(mode)) - return htonl(S_IFLNK); + return S_IFLNK; if (S_ISDIR(mode) || S_ISGITLINK(mode)) - return htonl(S_IFGITLINK); - return htonl(S_IFREG | ce_permissions(mode)); + return S_IFGITLINK; + return S_IFREG | ce_permissions(mode); } static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode) { extern int trust_executable_bit, has_symlinks; if (!has_symlinks && S_ISREG(mode) && - ce && S_ISLNK(ntohl(ce->ce_mode))) + ce && S_ISLNK(ce->ce_mode)) return ce->ce_mode; if (!trust_executable_bit && S_ISREG(mode)) { - if (ce && S_ISREG(ntohl(ce->ce_mode))) + if (ce && S_ISREG(ce->ce_mode)) return ce->ce_mode; return create_ce_mode(0666); } @@ -146,14 +164,14 @@ static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned in S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK) #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7) +#define ondisk_cache_entry_size(len) ((offsetof(struct ondisk_cache_entry,name) + (len) + 8) & ~7) struct index_state { struct cache_entry **cache; unsigned int cache_nr, cache_alloc, cache_changed; struct cache_tree *cache_tree; time_t timestamp; - void *mmap; - size_t mmap_size; + void *alloc; }; extern struct index_state the_index; diff --git a/diff-lib.c b/diff-lib.c index d85d8f34ba..4a05b02cd0 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -37,7 +37,7 @@ static int get_mode(const char *path, int *mode) if (!path || !strcmp(path, "/dev/null")) *mode = 0; else if (!strcmp(path, "-")) - *mode = ntohl(create_ce_mode(0666)); + *mode = create_ce_mode(0666); else if (stat(path, &st)) return error("Could not access '%s'", path); else @@ -384,7 +384,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) continue; } else - dpath->mode = ntohl(ce_mode_from_stat(ce, st.st_mode)); + dpath->mode = ce_mode_from_stat(ce, st.st_mode); while (i < entries) { struct cache_entry *nce = active_cache[i]; @@ -398,10 +398,10 @@ int run_diff_files(struct rev_info *revs, unsigned int option) */ stage = ce_stage(nce); if (2 <= stage) { - int mode = ntohl(nce->ce_mode); + int mode = nce->ce_mode; num_compare_stages++; hashcpy(dpath->parent[stage-2].sha1, nce->sha1); - dpath->parent[stage-2].mode = ntohl(ce_mode_from_stat(nce, mode)); + dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode); dpath->parent[stage-2].status = DIFF_STATUS_MODIFIED; } @@ -442,15 +442,15 @@ int run_diff_files(struct rev_info *revs, unsigned int option) } if (silent_on_removed) continue; - diff_addremove(&revs->diffopt, '-', ntohl(ce->ce_mode), + diff_addremove(&revs->diffopt, '-', ce->ce_mode, ce->sha1, ce->name, NULL); continue; } changed = ce_match_stat(ce, &st, ce_option); if (!changed && !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) continue; - oldmode = ntohl(ce->ce_mode); - newmode = ntohl(ce_mode_from_stat(ce, st.st_mode)); + oldmode = ce->ce_mode; + newmode = ce_mode_from_stat(ce, st.st_mode); diff_change(&revs->diffopt, oldmode, newmode, ce->sha1, (changed ? null_sha1 : ce->sha1), ce->name, NULL); @@ -471,7 +471,7 @@ static void diff_index_show_file(struct rev_info *revs, struct cache_entry *ce, unsigned char *sha1, unsigned int mode) { - diff_addremove(&revs->diffopt, prefix[0], ntohl(mode), + diff_addremove(&revs->diffopt, prefix[0], mode, sha1, ce->name, NULL); } @@ -550,14 +550,14 @@ static int show_modified(struct rev_info *revs, p->len = pathlen; memcpy(p->path, new->name, pathlen); p->path[pathlen] = 0; - p->mode = ntohl(mode); + p->mode = mode; hashclr(p->sha1); memset(p->parent, 0, 2 * sizeof(struct combine_diff_parent)); p->parent[0].status = DIFF_STATUS_MODIFIED; - p->parent[0].mode = ntohl(new->ce_mode); + p->parent[0].mode = new->ce_mode; hashcpy(p->parent[0].sha1, new->sha1); p->parent[1].status = DIFF_STATUS_MODIFIED; - p->parent[1].mode = ntohl(old->ce_mode); + p->parent[1].mode = old->ce_mode; hashcpy(p->parent[1].sha1, old->sha1); show_combined_diff(p, 2, revs->dense_combined_merges, revs); free(p); @@ -569,9 +569,6 @@ static int show_modified(struct rev_info *revs, !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) return 0; - mode = ntohl(mode); - oldmode = ntohl(oldmode); - diff_change(&revs->diffopt, oldmode, mode, old->sha1, sha1, old->name, NULL); return 0; @@ -628,7 +625,7 @@ static int diff_cache(struct rev_info *revs, cached, match_missing)) break; diff_unmerge(&revs->diffopt, ce->name, - ntohl(ce->ce_mode), ce->sha1); + ce->ce_mode, ce->sha1); break; case 3: diff_unmerge(&revs->diffopt, ce->name, @@ -664,7 +661,7 @@ static void mark_merge_entries(void) struct cache_entry *ce = active_cache[i]; if (!ce_stage(ce)) continue; - ce->ce_flags |= htons(CE_STAGEMASK); + ce->ce_flags |= CE_STAGEMASK; } } @@ -722,8 +719,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) cache_tree_invalidate_path(active_cache_tree, ce->name); last = ce; - ce->ce_mode = 0; - ce->ce_flags &= ~htons(CE_STAGEMASK); + ce->ce_flags |= CE_REMOVE; } *dst++ = ce; } diff --git a/dir.c b/dir.c index 3e345c2fc5..1b9cc7a8a8 100644 --- a/dir.c +++ b/dir.c @@ -391,7 +391,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len) break; if (endchar == '/') return index_directory; - if (!endchar && S_ISGITLINK(ntohl(ce->ce_mode))) + if (!endchar && S_ISGITLINK(ce->ce_mode)) return index_gitdir; } return index_nonexistent; diff --git a/entry.c b/entry.c index 257ab46e94..44f4b897d4 100644 --- a/entry.c +++ b/entry.c @@ -103,7 +103,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout int fd; long wrote; - switch (ntohl(ce->ce_mode) & S_IFMT) { + switch (ce->ce_mode & S_IFMT) { char *new; struct strbuf buf; unsigned long size; @@ -129,7 +129,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout strcpy(path, ".merge_file_XXXXXX"); fd = mkstemp(path); } else - fd = create_file(path, ntohl(ce->ce_mode)); + fd = create_file(path, ce->ce_mode); if (fd < 0) { free(new); return error("git-checkout-index: unable to create file %s (%s)", @@ -221,7 +221,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t unlink(path); if (S_ISDIR(st.st_mode)) { /* If it is a gitlink, leave it alone! */ - if (S_ISGITLINK(ntohl(ce->ce_mode))) + if (S_ISGITLINK(ce->ce_mode)) return 0; if (!state->force) return error("%s is a directory", path); diff --git a/merge-index.c b/merge-index.c index fa719cb0b1..bbb700b54e 100644 --- a/merge-index.c +++ b/merge-index.c @@ -48,7 +48,7 @@ static int merge_entry(int pos, const char *path) break; found++; strcpy(hexbuf[stage], sha1_to_hex(ce->sha1)); - sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode)); + sprintf(ownbuf[stage], "%o", ce->ce_mode); arguments[stage] = hexbuf[stage]; arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); diff --git a/merge-recursive.c b/merge-recursive.c index c292a77a81..bdf03b1f1f 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -333,7 +333,7 @@ static struct path_list *get_unmerged(void) item->util = xcalloc(1, sizeof(struct stage_data)); } e = item->util; - e->stages[ce_stage(ce)].mode = ntohl(ce->ce_mode); + e->stages[ce_stage(ce)].mode = ce->ce_mode; hashcpy(e->stages[ce_stage(ce)].sha, ce->sha1); } diff --git a/reachable.c b/reachable.c index 6383401e2d..00f289f2f4 100644 --- a/reachable.c +++ b/reachable.c @@ -176,7 +176,7 @@ static void add_cache_refs(struct rev_info *revs) * lookup_blob() on them, to avoid populating the hash table * with invalid information */ - if (S_ISGITLINK(ntohl(active_cache[i]->ce_mode))) + if (S_ISGITLINK(active_cache[i]->ce_mode)) continue; lookup_blob(active_cache[i]->sha1); diff --git a/read-cache.c b/read-cache.c index 7db55883d6..82a6238b77 100644 --- a/read-cache.c +++ b/read-cache.c @@ -30,20 +30,16 @@ struct index_state the_index; */ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) { - ce->ce_ctime.sec = htonl(st->st_ctime); - ce->ce_mtime.sec = htonl(st->st_mtime); -#ifdef USE_NSEC - ce->ce_ctime.nsec = htonl(st->st_ctim.tv_nsec); - ce->ce_mtime.nsec = htonl(st->st_mtim.tv_nsec); -#endif - ce->ce_dev = htonl(st->st_dev); - ce->ce_ino = htonl(st->st_ino); - ce->ce_uid = htonl(st->st_uid); - ce->ce_gid = htonl(st->st_gid); - ce->ce_size = htonl(st->st_size); + ce->ce_ctime = st->st_ctime; + ce->ce_mtime = st->st_mtime; + ce->ce_dev = st->st_dev; + ce->ce_ino = st->st_ino; + ce->ce_uid = st->st_uid; + ce->ce_gid = st->st_gid; + ce->ce_size = st->st_size; if (assume_unchanged) - ce->ce_flags |= htons(CE_VALID); + ce->ce_flags |= CE_VALID; } static int ce_compare_data(struct cache_entry *ce, struct stat *st) @@ -116,7 +112,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return DATA_CHANGED; break; case S_IFDIR: - if (S_ISGITLINK(ntohl(ce->ce_mode))) + if (S_ISGITLINK(ce->ce_mode)) return 0; default: return TYPE_CHANGED; @@ -128,14 +124,17 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) { unsigned int changed = 0; - switch (ntohl(ce->ce_mode) & S_IFMT) { + if (ce->ce_flags & CE_REMOVE) + return MODE_CHANGED | DATA_CHANGED | TYPE_CHANGED; + + switch (ce->ce_mode & S_IFMT) { case S_IFREG: changed |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0; /* We consider only the owner x bit to be relevant for * "mode changes" */ if (trust_executable_bit && - (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))) + (0100 & (ce->ce_mode ^ st->st_mode))) changed |= MODE_CHANGED; break; case S_IFLNK: @@ -149,32 +148,18 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) else if (ce_compare_gitlink(ce)) changed |= DATA_CHANGED; return changed; - case 0: /* Special case: unmerged file in index */ - return MODE_CHANGED | DATA_CHANGED | TYPE_CHANGED; default: - die("internal error: ce_mode is %o", ntohl(ce->ce_mode)); + die("internal error: ce_mode is %o", ce->ce_mode); } - if (ce->ce_mtime.sec != htonl(st->st_mtime)) - changed |= MTIME_CHANGED; - if (ce->ce_ctime.sec != htonl(st->st_ctime)) - changed |= CTIME_CHANGED; - -#ifdef USE_NSEC - /* - * nsec seems unreliable - not all filesystems support it, so - * as long as it is in the inode cache you get right nsec - * but after it gets flushed, you get zero nsec. - */ - if (ce->ce_mtime.nsec != htonl(st->st_mtim.tv_nsec)) + if (ce->ce_mtime != (unsigned int) st->st_mtime) changed |= MTIME_CHANGED; - if (ce->ce_ctime.nsec != htonl(st->st_ctim.tv_nsec)) + if (ce->ce_ctime != (unsigned int) st->st_ctime) changed |= CTIME_CHANGED; -#endif - if (ce->ce_uid != htonl(st->st_uid) || - ce->ce_gid != htonl(st->st_gid)) + if (ce->ce_uid != (unsigned int) st->st_uid || + ce->ce_gid != (unsigned int) st->st_gid) changed |= OWNER_CHANGED; - if (ce->ce_ino != htonl(st->st_ino)) + if (ce->ce_ino != (unsigned int) st->st_ino) changed |= INODE_CHANGED; #ifdef USE_STDEV @@ -183,11 +168,11 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) * clients will have different views of what "device" * the filesystem is on */ - if (ce->ce_dev != htonl(st->st_dev)) + if (ce->ce_dev != (unsigned int) st->st_dev) changed |= INODE_CHANGED; #endif - if (ce->ce_size != htonl(st->st_size)) + if (ce->ce_size != (unsigned int) st->st_size) changed |= DATA_CHANGED; return changed; @@ -205,7 +190,7 @@ int ie_match_stat(struct index_state *istate, * If it's marked as always valid in the index, it's * valid whatever the checked-out copy says. */ - if (!ignore_valid && (ce->ce_flags & htons(CE_VALID))) + if (!ignore_valid && (ce->ce_flags & CE_VALID)) return 0; changed = ce_match_stat_basic(ce, st); @@ -228,7 +213,7 @@ int ie_match_stat(struct index_state *istate, */ if (!changed && istate->timestamp && - istate->timestamp <= ntohl(ce->ce_mtime.sec)) { + istate->timestamp <= ce->ce_mtime) { if (assume_racy_is_modified) changed |= DATA_CHANGED; else @@ -257,7 +242,7 @@ int ie_modified(struct index_state *istate, * the length field is zero. For other cases the ce_size * should match the SHA1 recorded in the index entry. */ - if ((changed & DATA_CHANGED) && ce->ce_size != htonl(0)) + if ((changed & DATA_CHANGED) && ce->ce_size != 0) return changed; changed_fs = ce_modified_check_fs(ce, st); @@ -320,7 +305,7 @@ int index_name_pos(struct index_state *istate, const char *name, int namelen) while (last > first) { int next = (last + first) >> 1; struct cache_entry *ce = istate->cache[next]; - int cmp = cache_name_compare(name, namelen, ce->name, ntohs(ce->ce_flags)); + int cmp = cache_name_compare(name, namelen, ce->name, ce->ce_flags); if (!cmp) return next; if (cmp < 0) { @@ -405,7 +390,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) size = cache_entry_size(namelen); ce = xcalloc(1, size); memcpy(ce->name, path, namelen); - ce->ce_flags = htons(namelen); + ce->ce_flags = namelen; fill_stat_cache_info(ce, &st); if (trust_executable_bit && has_symlinks) @@ -583,7 +568,7 @@ static int has_file_name(struct index_state *istate, continue; if (p->name[len] != '/') continue; - if (!ce_stage(p) && !p->ce_mode) + if (p->ce_flags & CE_REMOVE) continue; retval = -1; if (!ok_to_replace) @@ -616,7 +601,7 @@ static int has_dir_name(struct index_state *istate, } len = slash - name; - pos = index_name_pos(istate, name, ntohs(create_ce_flags(len, stage))); + pos = index_name_pos(istate, name, create_ce_flags(len, stage)); if (pos >= 0) { /* * Found one, but not so fast. This could @@ -679,7 +664,7 @@ static int check_file_directory_conflict(struct index_state *istate, /* * When ce is an "I am going away" entry, we allow it to be added */ - if (!ce_stage(ce) && !ce->ce_mode) + if (ce->ce_flags & CE_REMOVE) return 0; /* @@ -704,7 +689,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK; cache_tree_invalidate_path(istate->cache_tree, ce->name); - pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags)); + pos = index_name_pos(istate, ce->name, ce->ce_flags); /* existing match? Just replace it. */ if (pos >= 0) { @@ -736,7 +721,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e if (!ok_to_replace) return error("'%s' appears as both a file and as a directory", ce->name); - pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags)); + pos = index_name_pos(istate, ce->name, ce->ce_flags); pos = -pos-1; } return pos + 1; @@ -810,7 +795,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, * valid again, under "assume unchanged" mode. */ if (ignore_valid && assume_unchanged && - !(ce->ce_flags & htons(CE_VALID))) + !(ce->ce_flags & CE_VALID)) ; /* mark this one VALID again */ else return ce; @@ -826,7 +811,6 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, updated = xmalloc(size); memcpy(updated, ce, size); fill_stat_cache_info(updated, &st); - /* * If ignore_valid is not set, we should leave CE_VALID bit * alone. Otherwise, paths marked with --no-assume-unchanged @@ -834,8 +818,8 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, * automatically, which is not really what we want. */ if (!ignore_valid && assume_unchanged && - !(ce->ce_flags & htons(CE_VALID))) - updated->ce_flags &= ~htons(CE_VALID); + !(ce->ce_flags & CE_VALID)) + updated->ce_flags &= ~CE_VALID; return updated; } @@ -880,7 +864,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p /* If we are doing --really-refresh that * means the index is not valid anymore. */ - ce->ce_flags &= ~htons(CE_VALID); + ce->ce_flags &= ~CE_VALID; istate->cache_changed = 1; } if (quiet) @@ -942,16 +926,34 @@ int read_index(struct index_state *istate) return read_index_from(istate, get_index_file()); } +static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce) +{ + ce->ce_ctime = ntohl(ondisk->ctime.sec); + ce->ce_mtime = ntohl(ondisk->mtime.sec); + ce->ce_dev = ntohl(ondisk->dev); + ce->ce_ino = ntohl(ondisk->ino); + ce->ce_mode = ntohl(ondisk->mode); + ce->ce_uid = ntohl(ondisk->uid); + ce->ce_gid = ntohl(ondisk->gid); + ce->ce_size = ntohl(ondisk->size); + /* On-disk flags are just 16 bits */ + ce->ce_flags = ntohs(ondisk->flags); + hashcpy(ce->sha1, ondisk->sha1); + memcpy(ce->name, ondisk->name, ce_namelen(ce)+1); +} + /* remember to discard_cache() before reading a different cache! */ int read_index_from(struct index_state *istate, const char *path) { int fd, i; struct stat st; - unsigned long offset; + unsigned long src_offset, dst_offset; struct cache_header *hdr; + void *mmap; + size_t mmap_size; errno = EBUSY; - if (istate->mmap) + if (istate->alloc) return istate->cache_nr; errno = ENOENT; @@ -967,31 +969,47 @@ int read_index_from(struct index_state *istate, const char *path) die("cannot stat the open index (%s)", strerror(errno)); errno = EINVAL; - istate->mmap_size = xsize_t(st.st_size); - if (istate->mmap_size < sizeof(struct cache_header) + 20) + mmap_size = xsize_t(st.st_size); + if (mmap_size < sizeof(struct cache_header) + 20) die("index file smaller than expected"); - istate->mmap = xmmap(NULL, istate->mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); close(fd); + if (mmap == MAP_FAILED) + die("unable to map index file"); - hdr = istate->mmap; - if (verify_hdr(hdr, istate->mmap_size) < 0) + hdr = mmap; + if (verify_hdr(hdr, mmap_size) < 0) goto unmap; istate->cache_nr = ntohl(hdr->hdr_entries); istate->cache_alloc = alloc_nr(istate->cache_nr); istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *)); - offset = sizeof(*hdr); + /* + * The disk format is actually larger than the in-memory format, + * due to space for nsec etc, so even though the in-memory one + * has room for a few more flags, we can allocate using the same + * index size + */ + istate->alloc = xmalloc(mmap_size); + + src_offset = sizeof(*hdr); + dst_offset = 0; for (i = 0; i < istate->cache_nr; i++) { + struct ondisk_cache_entry *disk_ce; struct cache_entry *ce; - ce = (struct cache_entry *)((char *)(istate->mmap) + offset); - offset = offset + ce_size(ce); + disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset); + ce = (struct cache_entry *)((char *)istate->alloc + dst_offset); + convert_from_disk(disk_ce, ce); istate->cache[i] = ce; + + src_offset += ondisk_ce_size(ce); + dst_offset += ce_size(ce); } istate->timestamp = st.st_mtime; - while (offset <= istate->mmap_size - 20 - 8) { + while (src_offset <= mmap_size - 20 - 8) { /* After an array of active_nr index entries, * there can be arbitrary number of extended * sections, each of which is prefixed with @@ -999,40 +1017,36 @@ int read_index_from(struct index_state *istate, const char *path) * in 4-byte network byte order. */ unsigned long extsize; - memcpy(&extsize, (char *)(istate->mmap) + offset + 4, 4); + memcpy(&extsize, (char *)mmap + src_offset + 4, 4); extsize = ntohl(extsize); if (read_index_extension(istate, - ((const char *) (istate->mmap)) + offset, - (char *) (istate->mmap) + offset + 8, + (const char *) mmap + src_offset, + (char *) mmap + src_offset + 8, extsize) < 0) goto unmap; - offset += 8; - offset += extsize; + src_offset += 8; + src_offset += extsize; } + munmap(mmap, mmap_size); return istate->cache_nr; unmap: - munmap(istate->mmap, istate->mmap_size); + munmap(mmap, mmap_size); errno = EINVAL; die("index file corrupt"); } int discard_index(struct index_state *istate) { - int ret; - istate->cache_nr = 0; istate->cache_changed = 0; istate->timestamp = 0; cache_tree_free(&(istate->cache_tree)); - if (istate->mmap == NULL) - return 0; - ret = munmap(istate->mmap, istate->mmap_size); - istate->mmap = NULL; - istate->mmap_size = 0; + free(istate->alloc); + istate->alloc = NULL; /* no need to throw away allocated active_cache */ - return ret; + return 0; } #define WRITE_BUFFER_SIZE 8192 @@ -1144,10 +1158,32 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) * file, and never calls us, so the cached size information * for "frotz" stays 6 which does not match the filesystem. */ - ce->ce_size = htonl(0); + ce->ce_size = 0; } } +static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce) +{ + int size = ondisk_ce_size(ce); + struct ondisk_cache_entry *ondisk = xcalloc(1, size); + + ondisk->ctime.sec = htonl(ce->ce_ctime); + ondisk->ctime.nsec = 0; + ondisk->mtime.sec = htonl(ce->ce_mtime); + ondisk->mtime.nsec = 0; + ondisk->dev = htonl(ce->ce_dev); + ondisk->ino = htonl(ce->ce_ino); + ondisk->mode = htonl(ce->ce_mode); + ondisk->uid = htonl(ce->ce_uid); + ondisk->gid = htonl(ce->ce_gid); + ondisk->size = htonl(ce->ce_size); + hashcpy(ondisk->sha1, ce->sha1); + ondisk->flags = htons(ce->ce_flags); + memcpy(ondisk->name, ce->name, ce_namelen(ce)); + + return ce_write(c, fd, ondisk, size); +} + int write_index(struct index_state *istate, int newfd) { SHA_CTX c; @@ -1157,7 +1193,7 @@ int write_index(struct index_state *istate, int newfd) int entries = istate->cache_nr; for (i = removed = 0; i < entries; i++) - if (!cache[i]->ce_mode) + if (cache[i]->ce_flags & CE_REMOVE) removed++; hdr.hdr_signature = htonl(CACHE_SIGNATURE); @@ -1170,12 +1206,12 @@ int write_index(struct index_state *istate, int newfd) for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; - if (!ce->ce_mode) + if (ce->ce_flags & CE_REMOVE) continue; if (istate->timestamp && - istate->timestamp <= ntohl(ce->ce_mtime.sec)) + istate->timestamp <= ce->ce_mtime) ce_smudge_racily_clean_entry(ce); - if (ce_write(&c, newfd, ce, ce_size(ce)) < 0) + if (ce_write_entry(&c, newfd, ce) < 0) return -1; } diff --git a/sha1_name.c b/sha1_name.c index 13e11645e1..be8489e4e5 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -695,7 +695,7 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode) break; if (ce_stage(ce) == stage) { hashcpy(sha1, ce->sha1); - *mode = ntohl(ce->ce_mode); + *mode = ce->ce_mode; return 0; } pos++; diff --git a/tree.c b/tree.c index 8c0819fa72..87708ef420 100644 --- a/tree.c +++ b/tree.c @@ -142,8 +142,8 @@ static int cmp_cache_name_compare(const void *a_, const void *b_) ce1 = *((const struct cache_entry **)a_); ce2 = *((const struct cache_entry **)b_); - return cache_name_compare(ce1->name, ntohs(ce1->ce_flags), - ce2->name, ntohs(ce2->ce_flags)); + return cache_name_compare(ce1->name, ce1->ce_flags, + ce2->name, ce2->ce_flags); } int read_tree(struct tree *tree, int stage, const char **match) diff --git a/unpack-trees.c b/unpack-trees.c index aa2513ed79..ff46fd62fd 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -289,7 +289,6 @@ static struct checkout state; static void check_updates(struct cache_entry **src, int nr, struct unpack_trees_options *o) { - unsigned short mask = htons(CE_UPDATE); unsigned cnt = 0, total = 0; struct progress *progress = NULL; char last_symlink[PATH_MAX]; @@ -297,7 +296,7 @@ static void check_updates(struct cache_entry **src, int nr, if (o->update && o->verbose_update) { for (total = cnt = 0; cnt < nr; cnt++) { struct cache_entry *ce = src[cnt]; - if (!ce->ce_mode || ce->ce_flags & mask) + if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) total++; } @@ -310,15 +309,15 @@ static void check_updates(struct cache_entry **src, int nr, while (nr--) { struct cache_entry *ce = *src++; - if (!ce->ce_mode || ce->ce_flags & mask) + if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) display_progress(progress, ++cnt); - if (!ce->ce_mode) { + if (ce->ce_flags & CE_REMOVE) { if (o->update) unlink_entry(ce->name, last_symlink); continue; } - if (ce->ce_flags & mask) { - ce->ce_flags &= ~mask; + if (ce->ce_flags & CE_UPDATE) { + ce->ce_flags &= ~CE_UPDATE; if (o->update) { checkout_entry(ce, &state, NULL); *last_symlink = '\0'; @@ -408,7 +407,7 @@ static void verify_uptodate(struct cache_entry *ce, * submodules that are marked to be automatically * checked out. */ - if (S_ISGITLINK(ntohl(ce->ce_mode))) + if (S_ISGITLINK(ce->ce_mode)) return; errno = 0; } @@ -450,7 +449,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, int cnt = 0; unsigned char sha1[20]; - if (S_ISGITLINK(ntohl(ce->ce_mode)) && + if (S_ISGITLINK(ce->ce_mode) && resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) { /* If we are not going to update the submodule, then * we don't care. @@ -481,7 +480,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, */ if (!ce_stage(ce)) { verify_uptodate(ce, o); - ce->ce_mode = 0; + ce->ce_flags |= CE_REMOVE; } cnt++; } @@ -568,7 +567,7 @@ static void verify_absent(struct cache_entry *ce, const char *action, cnt = cache_name_pos(ce->name, strlen(ce->name)); if (0 <= cnt) { struct cache_entry *ce = active_cache[cnt]; - if (!ce_stage(ce) && !ce->ce_mode) + if (ce->ce_flags & CE_REMOVE) return; } @@ -580,7 +579,7 @@ static void verify_absent(struct cache_entry *ce, const char *action, static int merged_entry(struct cache_entry *merge, struct cache_entry *old, struct unpack_trees_options *o) { - merge->ce_flags |= htons(CE_UPDATE); + merge->ce_flags |= CE_UPDATE; if (old) { /* * See if we can re-use the old CE directly? @@ -601,7 +600,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, invalidate_ce_path(merge); } - merge->ce_flags &= ~htons(CE_STAGEMASK); + merge->ce_flags &= ~CE_STAGEMASK; add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); return 1; } @@ -613,7 +612,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, verify_uptodate(old, o); else verify_absent(ce, "removed", o); - ce->ce_mode = 0; + ce->ce_flags |= CE_REMOVE; add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); invalidate_ce_path(ce); return 1; @@ -634,7 +633,7 @@ static void show_stage_entry(FILE *o, else fprintf(o, "%s%06o %s %d\t%s\n", label, - ntohl(ce->ce_mode), + ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce), ce->name); @@ -920,7 +919,7 @@ int oneway_merge(struct cache_entry **src, struct stat st; if (lstat(old->name, &st) || ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID)) - old->ce_flags |= htons(CE_UPDATE); + old->ce_flags |= CE_UPDATE; } return keep_entry(old, o); } -- cgit v1.3 From 5a9dd3998fb4c3ddc048cbcab74a8df72bff91b7 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Wed, 23 Jan 2008 11:21:22 -0600 Subject: git-commit: exit non-zero if we fail to commit the index In certain rare cases, the creation of the commit object and update of HEAD can succeed, but then installing the updated index will fail. This is most likely caused by a full disk or exceeded disk quota. When this happens the new index file will be removed, and the repository will be left with the original now-out-of-sync index. The user can recover with a "git reset HEAD" once the disk space issue is resolved. We should detect this failure and offer the user some helpful guidance. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- builtin-commit.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 02279360f7..d8deb1ad03 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -122,19 +122,23 @@ static void rollback_index_files(void) } } -static void commit_index_files(void) +static int commit_index_files(void) { + int err = 0; + switch (commit_style) { case COMMIT_AS_IS: break; /* nothing to do */ case COMMIT_NORMAL: - commit_lock_file(&index_lock); + err = commit_lock_file(&index_lock); break; case COMMIT_PARTIAL: - commit_lock_file(&index_lock); + err = commit_lock_file(&index_lock); rollback_lock_file(&false_lock); break; } + + return err; } /* @@ -926,7 +930,10 @@ int cmd_commit(int argc, const char **argv, const char *prefix) unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); - commit_index_files(); + if (commit_index_files()) + die ("Repository has been updated, but unable to write\n" + "new_index file. Check that disk is not full or quota is\n" + "not exceeded, and then \"git reset HEAD\" to recover."); rerere(); run_hook(get_index_file(), "post-commit", NULL); -- cgit v1.3 From 8a2f87332b847edc7f8fc5f305889c863651ecb5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 3 Feb 2008 00:00:09 -0800 Subject: Fix "git-commit -C $tag" The scripted version might not have handled this correctly either, but the version rewritten in C definitely does not grok this and complains $tag is not a commit object. Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- t/t7501-commit.sh | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index d8deb1ad03..c787bed696 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -601,7 +601,7 @@ static int parse_and_validate_options(int argc, const char *argv[], if (get_sha1(use_message, sha1)) die("could not lookup commit %s", use_message); - commit = lookup_commit(sha1); + commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) die("could not parse commit %s", use_message); diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index d1a415a126..55043d102f 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -327,4 +327,22 @@ test_expect_success 'amend using the message from another commit' ' ' +test_expect_success 'amend using the message from a commit named with tag' ' + + git reset --hard && + test_tick && + git commit --allow-empty -m "old commit" && + old=$(git rev-parse --verify HEAD) && + git tag -a -m "tag on old" tagged-old HEAD && + test_tick && + git commit --allow-empty -m "new commit" && + new=$(git rev-parse --verify HEAD) && + test_tick && + git commit --allow-empty --amend -C tagged-old && + git show --pretty="format:%ad %s" "$old" >expected && + git show --pretty="format:%ad %s" HEAD >actual && + diff -u expected actual + +' + test_done -- cgit v1.3 From 3473f3035d04957ca24d3ccc232f4263b26d6bb8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2008 11:01:44 +0100 Subject: git-commit: support variable number of hook arguments This is a preparatory patch to allow using run_hook for the prepare-commit-msg hook. Signed-off-by: Junio C Hamano --- builtin-commit.c | 61 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 26 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index c787bed696..ec00134f98 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -343,6 +343,40 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int return s.commitable; } +static int run_hook(const char *index_file, const char *name, ...) +{ + struct child_process hook; + const char *argv[10], *env[2]; + char index[PATH_MAX]; + va_list args; + int i; + + va_start(args, name); + argv[0] = git_path("hooks/%s", name); + i = 0; + do { + if (++i >= ARRAY_SIZE(argv)) + die ("run_hook(): too many arguments"); + argv[i] = va_arg(args, const char *); + } while (argv[i]); + va_end(args); + + snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); + env[0] = index; + env[1] = NULL; + + if (access(argv[0], X_OK) < 0) + return 0; + + memset(&hook, 0, sizeof(hook)); + hook.argv = argv; + hook.no_stdin = 1; + hook.stdout_to_stderr = 1; + hook.env = env; + + return run_command(&hook); +} + static const char sign_off_header[] = "Signed-off-by: "; static int prepare_log_message(const char *index_file, const char *prefix) @@ -677,31 +711,6 @@ int cmd_status(int argc, const char **argv, const char *prefix) return commitable ? 0 : 1; } -static int run_hook(const char *index_file, const char *name, const char *arg) -{ - struct child_process hook; - const char *argv[3], *env[2]; - char index[PATH_MAX]; - - argv[0] = git_path("hooks/%s", name); - argv[1] = arg; - argv[2] = NULL; - snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); - env[0] = index; - env[1] = NULL; - - if (access(argv[0], X_OK) < 0) - return 0; - - memset(&hook, 0, sizeof(hook)); - hook.argv = argv; - hook.no_stdin = 1; - hook.stdout_to_stderr = 1; - hook.env = env; - - return run_command(&hook); -} - static void print_summary(const char *prefix, const unsigned char *sha1) { struct rev_info rev; @@ -876,7 +885,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) launch_editor(git_path(commit_editmsg), NULL, env); } if (!no_verify && - run_hook(index_file, "commit-msg", git_path(commit_editmsg))) { + run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { rollback_index_files(); exit(1); } -- cgit v1.3 From 406400ce4f69e79b544dd3539a71b85d99331820 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2008 11:01:45 +0100 Subject: git-commit: set GIT_EDITOR=: if editor will not be launched This is a preparatory patch that provides a simple way for the future prepare-commit-msg hook to discover if the editor will be launched. Signed-off-by: Junio C Hamano --- Documentation/hooks.txt | 4 ++++ builtin-commit.c | 2 ++ 2 files changed, 6 insertions(+) (limited to 'builtin-commit.c') diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt index f110162b01..e8d80cfcdb 100644 --- a/Documentation/hooks.txt +++ b/Documentation/hooks.txt @@ -61,6 +61,10 @@ The default 'pre-commit' hook, when enabled, catches introduction of lines with trailing whitespaces and aborts the commit when such a line is found. +All the `git-commit` hooks are invoked with the environment +variable `GIT_EDITOR=:` if the command will not bring up an editor +to modify the commit message. + commit-msg ---------- diff --git a/builtin-commit.c b/builtin-commit.c index ec00134f98..90ddbaebf8 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -599,6 +599,8 @@ static int parse_and_validate_options(int argc, const char *argv[], use_editor = 0; if (edit_flag) use_editor = 1; + if (!use_editor) + setenv("GIT_EDITOR", ":", 1); if (get_sha1("HEAD", head_sha1)) initial_commit = 1; -- cgit v1.3 From ec84bd000a89e657b36136ec927144cd13f26079 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2008 11:01:46 +0100 Subject: git-commit: Refactor creation of log message. This patch moves the code of run_commit, up to writing the trees, editing the message and running the commit-msg hook to prepare_log_message. It also renames the latter to prepare_to_commit. This simplifies a little the code for the next patch. Signed-off-by: Junio C Hamano --- builtin-commit.c | 171 ++++++++++++++++++++++++++++-------------------------- t/t7502-commit.sh | 29 +++++++++ 2 files changed, 117 insertions(+), 83 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 90ddbaebf8..e8cb320590 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -377,9 +377,17 @@ static int run_hook(const char *index_file, const char *name, ...) return run_command(&hook); } +static int is_a_merge(const unsigned char *sha1) +{ + struct commit *commit = lookup_commit(sha1); + if (!commit || parse_commit(commit)) + die("could not parse HEAD commit"); + return !!(commit->parents && commit->parents->next); +} + static const char sign_off_header[] = "Signed-off-by: "; -static int prepare_log_message(const char *index_file, const char *prefix) +static int prepare_to_commit(const char *index_file, const char *prefix) { struct stat statbuf; int commitable, saved_color_setting; @@ -387,6 +395,9 @@ static int prepare_log_message(const char *index_file, const char *prefix) char *buffer; FILE *fp; + if (!no_verify && run_hook(index_file, "pre-commit", NULL)) + return 0; + strbuf_init(&sb, 0); if (message.len) { strbuf_addbuf(&sb, &message); @@ -447,13 +458,38 @@ static int prepare_log_message(const char *index_file, const char *prefix) strbuf_release(&sb); - if (!use_editor) { + if (use_editor) { + 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); + + 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"; - fclose(fp); - if (!active_nr && read_cache() < 0) die("Cannot read index"); @@ -461,48 +497,56 @@ static int prepare_log_message(const char *index_file, const char *prefix) parent = "HEAD^1"; if (get_sha1(parent, sha1)) - return !!active_nr; + 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); + } + } - 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 */); + 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; + } - return !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); + /* + * 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 (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); - - 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; + 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); + } - fclose(fp); + if (!no_verify && + run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { + return 0; + } - return commitable; + return 1; } /* @@ -761,14 +805,6 @@ int git_commit_config(const char *k, const char *v) return git_status_config(k, v); } -static int is_a_merge(const unsigned char *sha1) -{ - struct commit *commit = lookup_commit(sha1); - if (!commit || parse_commit(commit)) - die("could not parse HEAD commit"); - return !!(commit->parents && commit->parents->next); -} - static const char commit_utf8_warn[] = "Warning: commit message does not conform to UTF-8.\n" "You may want to amend it after fixing the message, or set the config\n" @@ -800,33 +836,13 @@ int cmd_commit(int argc, const char **argv, const char *prefix) index_file = prepare_index(argc, argv, prefix); - if (!no_verify && run_hook(index_file, "pre-commit", NULL)) { - rollback_index_files(); - return 1; - } - - if (!prepare_log_message(index_file, prefix) && !in_merge && - !allow_empty && !(amend && is_a_merge(head_sha1))) { - run_status(stdout, index_file, prefix, 0); + /* Set up everything for writing the commit object. This includes + running hooks, writing the trees, and interacting with the user. */ + if (!prepare_to_commit(index_file, prefix)) { rollback_index_files(); - unlink(commit_editmsg); return 1; } - /* - * Re-read the index as pre-commit hook could have updated it, - * and write it out as a tree. - */ - 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) { - rollback_index_files(); - die("Error building trees"); - } - /* * The commit object */ @@ -878,19 +894,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_addf(&sb, "encoding %s\n", git_commit_encoding); strbuf_addch(&sb, '\n'); - /* Get the commit message and validate it */ + /* Finally, get the commit message */ header_len = sb.len; - 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)) { - rollback_index_files(); - exit(1); - } if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { rollback_index_files(); die("could not read commit message"); diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index aaf497e6a5..b780fddc08 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -154,4 +154,33 @@ test_expect_success 'cleanup commit messages (strip,-F,-e)' ' ' +pwd=`pwd` +cat >> .git/FAKE_EDITOR << EOF +#! /bin/sh +echo editor started > "$pwd/.git/result" +exit 0 +EOF +chmod +x .git/FAKE_EDITOR + +test_expect_success 'do not fire editor in the presence of conflicts' ' + + git clean + echo f>g + git add g + git commit -myes + git branch second + echo master>g + echo g>h + git add g h + git commit -mmaster + git checkout second + echo second>g + git add g + git commit -msecond + git cherry-pick -n master + echo "editor not started" > .git/result + GIT_EDITOR=`pwd`/.git/FAKE_EDITOR git commit && exit 1 # should fail + test "`cat .git/result`" = "editor not started" +' + test_done -- cgit v1.3 From 8089c85bcba89464b9b2a32fa948ed85eb367e70 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 5 Feb 2008 08:04:18 +0100 Subject: git-commit: add a prepare-commit-msg hook The prepare-commit-msg hook is run whenever a "fresh" commit message is prepared, just before it is shown in the editor (if it is). Its purpose is to modify the commit message in-place. It takes one to three parameters. The first is the name of the file that the commit log message. The second is the source of the commit message, and can be: "message" (if a -m or -F option was given); "template" (if a -t option was given or the configuration option commit.template is set); "merge" (if the commit is a merge or a .git/MERGE_MSG file exists); "squash" (if a .git/SQUASH_MSG file exists); or "commit", followed by a commit SHA1 as the third parameter (if a -c, -C or --amend option was given). If its exit status is non-zero, git-commit will abort. The hook is not suppressed by the --no-verify option, so it should not be used as a replacement for the pre-commit hook. The sample prepare-commit-msg comments out the `Conflicts:` part of a merge's commit message; other examples are commented out, including adding a Signed-off-by line at the bottom of the commit messsage, that the user can then edit or discard altogether. Signed-off-by: Paolo Bonzini Signed-off-by: Junio C Hamano --- Documentation/git-commit.txt | 4 +- Documentation/hooks.txt | 25 ++++++ builtin-commit.c | 21 +++++ t/t7505-prepare-commit-msg-hook.sh | 155 ++++++++++++++++++++++++++++++++++++ templates/hooks--commit-msg | 3 + templates/hooks--prepare-commit-msg | 36 +++++++++ 6 files changed, 242 insertions(+), 2 deletions(-) create mode 100755 t/t7505-prepare-commit-msg-hook.sh create mode 100644 templates/hooks--prepare-commit-msg (limited to 'builtin-commit.c') diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index c3725b2ed9..b4ae61ff46 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -280,8 +280,8 @@ order). HOOKS ----- -This command can run `commit-msg`, `pre-commit`, and -`post-commit` hooks. See link:hooks.html[hooks] for more +This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`, +and `post-commit` hooks. See link:hooks.html[hooks] for more information. diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt index e8d80cfcdb..76b8d77460 100644 --- a/Documentation/hooks.txt +++ b/Documentation/hooks.txt @@ -65,6 +65,31 @@ All the `git-commit` hooks are invoked with the environment variable `GIT_EDITOR=:` if the command will not bring up an editor to modify the commit message. +prepare-commit-msg +------------------ + +This hook is invoked by `git-commit` right after preparing the +default log message, and before the editor is started. + +It takes one to three parameters. The first is the name of the file +that the commit log message. The second is the source of the commit +message, and can be: `message` (if a `\-m` or `\-F` option was +given); `template` (if a `\-t` option was given or the +configuration option `commit.template` is set); `merge` (if the +commit is a merge or a `.git/MERGE_MSG` file exists); `squash` +(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by +a commit SHA1 (if a `\-c`, `\-C` or `\--amend` option was given). + +If the exit status is non-zero, `git-commit` will abort. + +The purpose of the hook is to edit the message file in place, and +it is not suppressed by the `\--no-verify` option. A non-zero exit +means a failure of the hook and aborts the commit. It should not +be used as replacement for pre-commit hook. + +The sample `prepare-commit-msg` hook that comes with git comments +out the `Conflicts:` part of a merge's commit message. + commit-msg ---------- diff --git a/builtin-commit.c b/builtin-commit.c index e8cb320590..03caa30f0e 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -394,6 +394,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix) struct strbuf sb; char *buffer; FILE *fp; + const char *hook_arg1 = NULL; + const char *hook_arg2 = NULL; if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; @@ -401,32 +403,47 @@ static int prepare_to_commit(const char *index_file, const char *prefix) 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)); @@ -534,6 +551,10 @@ static int prepare_to_commit(const char *index_file, const char *prefix) 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 }; diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh new file mode 100755 index 0000000000..7ddec99a64 --- /dev/null +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -0,0 +1,155 @@ +#!/bin/sh + +test_description='prepare-commit-msg hook' + +. ./test-lib.sh + +test_expect_success 'with no hook' ' + + echo "foo" > file && + git add file && + git commit -m "first" + +' + +# set up fake editor for interactive editing +cat > fake-editor <<'EOF' +#!/bin/sh +exit 0 +EOF +chmod +x fake-editor +FAKE_EDITOR="$(pwd)/fake-editor" +export FAKE_EDITOR + +# now install hook that always succeeds and adds a message +HOOKDIR="$(git rev-parse --git-dir)/hooks" +HOOK="$HOOKDIR/prepare-commit-msg" +mkdir -p "$HOOKDIR" +cat > "$HOOK" <<'EOF' +#!/bin/sh +if test "$2" = commit; then + source=$(git-rev-parse "$3") +else + source=${2-default} +fi +if test "$GIT_EDITOR" = :; then + sed -e "1s/.*/$source (no editor)/" "$1" > msg.tmp +else + sed -e "1s/.*/$source/" "$1" > msg.tmp +fi +mv msg.tmp "$1" +exit 0 +EOF +chmod +x "$HOOK" + +echo dummy template > "$(git rev-parse --git-dir)/template" + +test_expect_success 'with hook (-m)' ' + + echo "more" >> file && + git add file && + git commit -m "more" && + test "`git log -1 --pretty=format:%s`" = "message (no editor)" + +' + +test_expect_success 'with hook (-m editor)' ' + + echo "more" >> file && + git add file && + GIT_EDITOR="$FAKE_EDITOR" git commit -e -m "more more" && + test "`git log -1 --pretty=format:%s`" = message + +' + +test_expect_success 'with hook (-t)' ' + + echo "more" >> file && + git add file && + git commit -t "$(git rev-parse --git-dir)/template" && + test "`git log -1 --pretty=format:%s`" = template + +' + +test_expect_success 'with hook (-F)' ' + + echo "more" >> file && + git add file && + (echo more | git commit -F -) && + test "`git log -1 --pretty=format:%s`" = "message (no editor)" + +' + +test_expect_success 'with hook (-F editor)' ' + + echo "more" >> file && + git add file && + (echo more more | GIT_EDITOR="$FAKE_EDITOR" git commit -e -F -) && + test "`git log -1 --pretty=format:%s`" = message + +' + +test_expect_success 'with hook (-C)' ' + + head=`git rev-parse HEAD` && + echo "more" >> file && + git add file && + git commit -C $head && + test "`git log -1 --pretty=format:%s`" = "$head (no editor)" + +' + +test_expect_success 'with hook (editor)' ' + + echo "more more" >> file && + git add file && + GIT_EDITOR="$FAKE_EDITOR" git commit && + test "`git log -1 --pretty=format:%s`" = default + +' + +test_expect_success 'with hook (--amend)' ' + + head=`git rev-parse HEAD` && + echo "more" >> file && + git add file && + GIT_EDITOR="$FAKE_EDITOR" git commit --amend && + test "`git log -1 --pretty=format:%s`" = "$head" + +' + +test_expect_success 'with hook (-c)' ' + + head=`git rev-parse HEAD` && + echo "more" >> file && + git add file && + GIT_EDITOR="$FAKE_EDITOR" git commit -c $head && + test "`git log -1 --pretty=format:%s`" = "$head" + +' + +cat > "$HOOK" <<'EOF' +#!/bin/sh +exit 1 +EOF + +test_expect_success 'with failing hook' ' + + head=`git rev-parse HEAD` && + echo "more" >> file && + git add file && + ! GIT_EDITOR="$FAKE_EDITOR" git commit -c $head + +' + +test_expect_success 'with failing hook (--no-verify)' ' + + head=`git rev-parse HEAD` && + echo "more" >> file && + git add file && + ! GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify -c $head + +' + + +test_done diff --git a/templates/hooks--commit-msg b/templates/hooks--commit-msg index c5cdb9d7ee..4ef86eb244 100644 --- a/templates/hooks--commit-msg +++ b/templates/hooks--commit-msg @@ -9,6 +9,9 @@ # To enable this hook, make this file executable. # Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/templates/hooks--prepare-commit-msg b/templates/hooks--prepare-commit-msg new file mode 100644 index 0000000000..ff0f42a1d9 --- /dev/null +++ b/templates/hooks--prepare-commit-msg @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by git-commit with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, make this file executable. + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2 $3" in + merge) + sed -i '/^Conflicts:/,/#/!b;s/^/# &/;s/^# #/#/' "$1" ;; + +# ""|template) +# perl -i -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" -- cgit v1.3 From 203a2fe117070964a5bf7cc940a742cad7a19fca Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 7 Feb 2008 11:39:48 -0500 Subject: Allow callers of unpack_trees() to handle failure Return an error from unpack_trees() instead of calling die(), and exit with an error in read-tree, builtin-commit, and diff-lib. merge-recursive already expected an error return from unpack_trees, so it doesn't need to be changed. The merge function can return negative to abort. This will be used in builtin-checkout -m. Signed-off-by: Daniel Barkalow --- builtin-commit.c | 3 +- builtin-read-tree.c | 3 +- diff-lib.c | 6 ++-- unpack-trees.c | 85 ++++++++++++++++++++++++++++++----------------------- 4 files changed, 56 insertions(+), 41 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index c63ff826fc..5b5b7c0f4d 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -200,7 +200,8 @@ static void create_base_index(void) die("failed to unpack HEAD tree object"); parse_tree(tree); init_tree_desc(&t, tree->buffer, tree->size); - unpack_trees(1, &t, &opts); + if (unpack_trees(1, &t, &opts)) + exit(128); /* We've already reported the error, finish dying */ } static char *prepare_index(int argc, const char **argv, const char *prefix) diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 5785401753..1d9d125b91 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -268,7 +268,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) parse_tree(tree); init_tree_desc(t+i, tree->buffer, tree->size); } - unpack_trees(nr_trees, t, &opts); + if (unpack_trees(nr_trees, t, &opts)) + return 128; /* * When reading only one tree (either the most basic form, diff --git a/diff-lib.c b/diff-lib.c index 03eaa7cef3..94b150e830 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -737,7 +737,8 @@ int run_diff_index(struct rev_info *revs, int cached) opts.unpack_data = revs; init_tree_desc(&t, tree->buffer, tree->size); - unpack_trees(1, &t, &opts); + if (unpack_trees(1, &t, &opts)) + exit(128); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); @@ -789,6 +790,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) opts.unpack_data = &revs; init_tree_desc(&t, tree->buffer, tree->size); - unpack_trees(1, &t, &opts); + if (unpack_trees(1, &t, &opts)) + exit(128); return 0; } diff --git a/unpack-trees.c b/unpack-trees.c index ff46fd62fd..9e6587f661 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -219,6 +219,8 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len, } #endif ret = o->fn(src, o, remove); + if (ret < 0) + return ret; #if DBRT_DEBUG > 1 printf("Added %d entries\n", ret); @@ -359,7 +361,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options } if (o->trivial_merges_only && o->nontrivial_merge) - die("Merge requires file-level merging"); + return error("Merge requires file-level merging"); check_updates(active_cache, active_nr, o); return 0; @@ -367,10 +369,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options /* Here come the merge functions */ -static void reject_merge(struct cache_entry *ce) +static int reject_merge(struct cache_entry *ce) { - die("Entry '%s' would be overwritten by merge. Cannot merge.", - ce->name); + return error("Entry '%s' would be overwritten by merge. Cannot merge.", + ce->name); } static int same(struct cache_entry *a, struct cache_entry *b) @@ -388,18 +390,18 @@ static int same(struct cache_entry *a, struct cache_entry *b) * When a CE gets turned into an unmerged entry, we * want it to be up-to-date */ -static void verify_uptodate(struct cache_entry *ce, +static int verify_uptodate(struct cache_entry *ce, struct unpack_trees_options *o) { struct stat st; if (o->index_only || o->reset) - return; + return 0; if (!lstat(ce->name, &st)) { unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID); if (!changed) - return; + return 0; /* * NEEDSWORK: the current default policy is to allow * submodule to be out of sync wrt the supermodule @@ -408,12 +410,12 @@ static void verify_uptodate(struct cache_entry *ce, * checked out. */ if (S_ISGITLINK(ce->ce_mode)) - return; + return 0; errno = 0; } if (errno == ENOENT) - return; - die("Entry '%s' not uptodate. Cannot merge.", ce->name); + return 0; + return error("Entry '%s' not uptodate. Cannot merge.", ce->name); } static void invalidate_ce_path(struct cache_entry *ce) @@ -479,7 +481,8 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, * ce->name is an entry in the subdirectory. */ if (!ce_stage(ce)) { - verify_uptodate(ce, o); + if (verify_uptodate(ce, o)) + return -1; ce->ce_flags |= CE_REMOVE; } cnt++; @@ -498,8 +501,8 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, d.exclude_per_dir = o->dir->exclude_per_dir; i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL); if (i) - die("Updating '%s' would lose untracked files in it", - ce->name); + return error("Updating '%s' would lose untracked files in it", + ce->name); free(pathbuf); return cnt; } @@ -508,16 +511,16 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, * We do not want to remove or overwrite a working tree file that * is not tracked, unless it is ignored. */ -static void verify_absent(struct cache_entry *ce, const char *action, - struct unpack_trees_options *o) +static int verify_absent(struct cache_entry *ce, const char *action, + struct unpack_trees_options *o) { struct stat st; if (o->index_only || o->reset || !o->update) - return; + return 0; if (has_symlink_leading_path(ce->name, NULL)) - return; + return 0; if (!lstat(ce->name, &st)) { int cnt; @@ -527,7 +530,7 @@ static void verify_absent(struct cache_entry *ce, const char *action, * ce->name is explicitly excluded, so it is Ok to * overwrite it. */ - return; + return 0; if (S_ISDIR(st.st_mode)) { /* * We are checking out path "foo" and @@ -556,7 +559,7 @@ static void verify_absent(struct cache_entry *ce, const char *action, * deleted entries here. */ o->pos += cnt; - return; + return 0; } /* @@ -568,12 +571,13 @@ static void verify_absent(struct cache_entry *ce, const char *action, if (0 <= cnt) { struct cache_entry *ce = active_cache[cnt]; if (ce->ce_flags & CE_REMOVE) - return; + return 0; } - die("Untracked working tree file '%s' " - "would be %s by merge.", ce->name, action); + return error("Untracked working tree file '%s' " + "would be %s by merge.", ce->name, action); } + return 0; } static int merged_entry(struct cache_entry *merge, struct cache_entry *old, @@ -591,12 +595,14 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, if (same(old, merge)) { memcpy(merge, old, offsetof(struct cache_entry, name)); } else { - verify_uptodate(old, o); + if (verify_uptodate(old, o)) + return -1; invalidate_ce_path(old); } } else { - verify_absent(merge, "overwritten", o); + if (verify_absent(merge, "overwritten", o)) + return -1; invalidate_ce_path(merge); } @@ -608,10 +614,12 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, struct unpack_trees_options *o) { - if (old) - verify_uptodate(old, o); - else - verify_absent(ce, "removed", o); + if (old) { + if (verify_uptodate(old, o)) + return -1; + } else + if (verify_absent(ce, "removed", o)) + return -1; ce->ce_flags |= CE_REMOVE; add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); invalidate_ce_path(ce); @@ -699,7 +707,7 @@ int threeway_merge(struct cache_entry **stages, /* #14, #14ALT, #2ALT */ if (remote && !df_conflict_head && head_match && !remote_match) { if (index && !same(index, remote) && !same(index, head)) - reject_merge(index); + return reject_merge(index); return merged_entry(remote, index, o); } /* @@ -707,7 +715,7 @@ int threeway_merge(struct cache_entry **stages, * make sure that it matches head. */ if (index && !same(index, head)) { - reject_merge(index); + return reject_merge(index); } if (head) { @@ -758,8 +766,10 @@ int threeway_merge(struct cache_entry **stages, remove_entry(remove); if (index) return deleted_entry(index, index, o); - else if (ce && !head_deleted) - verify_absent(ce, "removed", o); + else if (ce && !head_deleted) { + if (verify_absent(ce, "removed", o)) + return -1; + } return 0; } /* @@ -775,7 +785,8 @@ int threeway_merge(struct cache_entry **stages, * conflict resolution files. */ if (index) { - verify_uptodate(index, o); + if (verify_uptodate(index, o)) + return -1; } remove_entry(remove); @@ -855,11 +866,11 @@ int twoway_merge(struct cache_entry **src, /* all other failures */ remove_entry(remove); if (oldtree) - reject_merge(oldtree); + return reject_merge(oldtree); if (current) - reject_merge(current); + return reject_merge(current); if (newtree) - reject_merge(newtree); + return reject_merge(newtree); return -1; } } @@ -886,7 +897,7 @@ int bind_merge(struct cache_entry **src, return error("Cannot do a bind merge of %d trees\n", o->merge_size); if (a && old) - die("Entry '%s' overlaps. Cannot bind.", a->name); + return error("Entry '%s' overlaps. Cannot bind.", a->name); if (!a) return keep_entry(old, o); else -- cgit v1.3 From 5a95b85566b1700e042fdce6ec2de9ce7b5a8787 Mon Sep 17 00:00:00 2001 From: Gerrit Pape Date: Fri, 8 Feb 2008 09:53:58 +0000 Subject: builtin-commit: remove .git/SQUASH_MSG upon successful commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After doing a merge --squash, and commit afterwards, the commit message template SQUASH_MSG in the git directory is not removed, which means that the content of SQUASH_MSG is used as default commit message for all subsequent commits. So have git commit remove the file SQUASH_MSG from the git directory upon a successful commit. The problem was discovered by Frédéric Brière, reported through http://bugs.debian.org/464656 Signed-off-by: Gerrit Pape Signed-off-by: Junio C Hamano --- builtin-commit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index c787bed696..3a47275b8c 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -929,6 +929,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) unlink(git_path("MERGE_HEAD")); unlink(git_path("MERGE_MSG")); + unlink(git_path("SQUASH_MSG")); if (commit_index_files()) die ("Repository has been updated, but unable to write\n" -- cgit v1.3 From d865eb2a0d5f121a46dfcc18c78e7f27e0af0fbc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 11 Feb 2008 10:46:39 -0800 Subject: builtin-commit.c: guard config parser from value=NULL commit.template configuration expects a string value. Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 3a47275b8c..a43f201995 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -743,6 +743,8 @@ static void print_summary(const char *prefix, const unsigned char *sha1) int git_commit_config(const char *k, const char *v) { if (!strcmp(k, "commit.template")) { + if (!v) + return config_error_nonbool(v); template_file = xstrdup(v); return 0; } -- cgit v1.3 From 959ba670ad7173bcb73afaca69625a5635f63b8b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 14 Feb 2008 12:18:23 -0500 Subject: commit: discard index after setting up partial commit There may still be some entries from the original index that should be discarded before we show the status. In particular, if a file was added in the index but not included in the partial commit, it would still show up in the status listing as staged for commit. Ultimately the correct fix is to keep the two states in separate index_state variables. Then we can avoid having to reload the cache from the temporary file altogether, and just point wt_status_print at the correct index. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-commit.c | 4 ++++ t/t7502-status.sh | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index a43f201995..45232a11c4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -317,6 +317,10 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) if (write_cache(fd, active_cache, active_nr) || close_lock_file(&false_lock)) die("unable to write temporary index file"); + + discard_cache(); + read_cache_from(false_lock.filename); + return false_lock.filename; } diff --git a/t/t7502-status.sh b/t/t7502-status.sh index b64ce30ff1..e00607490b 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -128,4 +128,25 @@ test_expect_success 'status without relative paths' ' ' +cat <expect +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# dir1/untracked +# dir2/ +# expect +# output +# untracked +EOF +test_expect_success 'status of partial commit excluding new file in index' ' + git status dir1/modified >output && + diff -u expect output +' + test_done -- cgit v1.3 From 6b2f2d9805dd22c6f74957e0d76a1d2921b40c16 Mon Sep 17 00:00:00 2001 From: Matthias Kestenholz Date: Mon, 18 Feb 2008 08:26:03 +0100 Subject: Add color.ui variable which globally enables colorization if set Signed-off-by: Matthias Kestenholz Signed-off-by: Junio C Hamano --- Documentation/config.txt | 7 +++++++ builtin-branch.c | 10 +++++++--- builtin-commit.c | 4 ++++ builtin-diff.c | 5 +++++ builtin-log.c | 17 +++++++++++++++++ color.c | 12 ++++++++++++ color.h | 11 +++++++++++ diff.c | 6 +++--- diff.h | 1 + wt-status.c | 6 +++--- 10 files changed, 70 insertions(+), 9 deletions(-) (limited to 'builtin-commit.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index f2f6a774e0..7b676710ba 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -489,6 +489,13 @@ color.status.:: commit.template:: Specify a file to use as the template for new commit messages. +color.ui:: + When set to `always`, always use colors in all git commands which + are capable of colored output. When false (or `never`), never. When + set to `true` or `auto`, use colors only when the output is to the + terminal. When more specific variables of color.* are set, they always + take precedence over this setting. Defaults to false. + diff.autorefreshindex:: When using `git diff` to compare with work tree files, do not consider stat-only change as changed. diff --git a/builtin-branch.c b/builtin-branch.c index e414c88983..9edf2eb816 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -31,7 +31,7 @@ static unsigned char head_sha1[20]; static int branch_track = 1; -static int branch_use_color; +static int branch_use_color = -1; static char branch_colors[][COLOR_MAXLEN] = { "\033[m", /* reset */ "", /* PLAIN (normal) */ @@ -79,12 +79,12 @@ static int git_branch_config(const char *var, const char *value) branch_track = git_config_bool(var, value); return 0; } - return git_default_config(var, value); + return git_color_default_config(var, value); } static const char *branch_get_color(enum color_branch ix) { - if (branch_use_color) + if (branch_use_color > 0) return branch_colors[ix]; return ""; } @@ -588,6 +588,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix) }; git_config(git_branch_config); + + if (branch_use_color == -1) + branch_use_color = git_use_color_default; + track = branch_track; argc = parse_options(argc, argv, options, builtin_branch_usage, 0); if (!!delete + !!rename + !!force_create > 1) diff --git a/builtin-commit.c b/builtin-commit.c index 6612b4f405..065e1f7b7f 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -7,6 +7,7 @@ #include "cache.h" #include "cache-tree.h" +#include "color.h" #include "dir.h" #include "builtin.h" #include "diff.h" @@ -771,6 +772,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) git_config(git_status_config); + if (wt_status_use_color == -1) + wt_status_use_color = git_use_color_default; + argc = parse_and_validate_options(argc, argv, builtin_status_usage); index_file = prepare_index(argc, argv, prefix); diff --git a/builtin-diff.c b/builtin-diff.c index 8d7a5697f2..8f53f52dcb 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -4,6 +4,7 @@ * Copyright (c) 2006 Junio C Hamano */ #include "cache.h" +#include "color.h" #include "commit.h" #include "blob.h" #include "tag.h" @@ -229,6 +230,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) prefix = setup_git_directory_gently(&nongit); git_config(git_diff_ui_config); + + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + init_revisions(&rev, prefix); rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; diff --git a/builtin-log.c b/builtin-log.c index 99d69f0791..f2216d3187 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -5,6 +5,7 @@ * 2006 Junio Hamano */ #include "cache.h" +#include "color.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -235,6 +236,10 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix) struct rev_info rev; git_config(git_log_config); + + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + init_revisions(&rev, prefix); rev.diff = 1; rev.simplify_history = 0; @@ -307,6 +312,10 @@ int cmd_show(int argc, const char **argv, const char *prefix) int i, count, ret = 0; git_config(git_log_config); + + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + init_revisions(&rev, prefix); rev.diff = 1; rev.combine_merges = 1; @@ -367,6 +376,10 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) struct rev_info rev; git_config(git_log_config); + + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + init_revisions(&rev, prefix); init_reflog_walk(&rev.reflog_info); rev.abbrev_commit = 1; @@ -395,6 +408,10 @@ int cmd_log(int argc, const char **argv, const char *prefix) struct rev_info rev; git_config(git_log_config); + + if (diff_use_color_default == -1) + diff_use_color_default = git_use_color_default; + init_revisions(&rev, prefix); rev.always_show_header = 1; cmd_log_init(argc, argv, prefix, &rev); diff --git a/color.c b/color.c index cb70340420..12a6453f90 100644 --- a/color.c +++ b/color.c @@ -3,6 +3,8 @@ #define COLOR_RESET "\033[m" +int git_use_color_default = 0; + static int parse_color(const char *name, int len) { static const char * const color_names[] = { @@ -143,6 +145,16 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty) return 0; } +int git_color_default_config(const char *var, const char *value) +{ + if (!strcmp(var, "color.ui")) { + git_use_color_default = git_config_colorbool(var, value, -1); + return 0; + } + + return git_default_config(var, value); +} + static int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args, const char *trail) { diff --git a/color.h b/color.h index ff63513d39..ecda5569a2 100644 --- a/color.h +++ b/color.h @@ -4,6 +4,17 @@ /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ #define COLOR_MAXLEN 24 +/* + * This variable stores the value of color.ui + */ +extern int git_use_color_default; + + +/* + * Use this instead of git_default_config if you need the value of color.ui. + */ +int git_color_default_config(const char *var, const char *value); + int git_config_colorbool(const char *var, const char *value, int stdout_is_tty); void color_parse(const char *var, const char *value, char *dst); int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); diff --git a/diff.c b/diff.c index 58fe7750f9..c30c252272 100644 --- a/diff.c +++ b/diff.c @@ -20,7 +20,7 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 100; -static int diff_use_color_default; +int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; @@ -191,7 +191,7 @@ int git_diff_basic_config(const char *var, const char *value) } } - return git_default_config(var, value); + return git_color_default_config(var, value); } static char *quote_two(const char *one, const char *two) @@ -2055,7 +2055,7 @@ void diff_setup(struct diff_options *options) options->change = diff_change; options->add_remove = diff_addremove; - if (diff_use_color_default) + if (diff_use_color_default > 0) DIFF_OPT_SET(options, COLOR_DIFF); else DIFF_OPT_CLR(options, COLOR_DIFF); diff --git a/diff.h b/diff.h index 073d5cbf1b..8e73f07d7e 100644 --- a/diff.h +++ b/diff.h @@ -174,6 +174,7 @@ extern void diff_unmerge(struct diff_options *, extern int git_diff_basic_config(const char *var, const char *value); extern int git_diff_ui_config(const char *var, const char *value); +extern int diff_use_color_default; extern void diff_setup(struct diff_options *); extern int diff_opt_parse(struct diff_options *, const char **, int); extern int diff_setup_done(struct diff_options *); diff --git a/wt-status.c b/wt-status.c index 0b060934e2..32d780af1e 100644 --- a/wt-status.c +++ b/wt-status.c @@ -9,7 +9,7 @@ #include "diffcore.h" int wt_status_relative_paths = 1; -int wt_status_use_color = 0; +int wt_status_use_color = -1; static char wt_status_colors[][COLOR_MAXLEN] = { "", /* WT_STATUS_HEADER: normal */ "\033[32m", /* WT_STATUS_UPDATED: green */ @@ -40,7 +40,7 @@ static int parse_status_slot(const char *var, int offset) static const char* color(int slot) { - return wt_status_use_color ? wt_status_colors[slot] : ""; + return wt_status_use_color > 0 ? wt_status_colors[slot] : ""; } void wt_status_prepare(struct wt_status *s) @@ -401,5 +401,5 @@ int git_status_config(const char *k, const char *v) wt_status_relative_paths = git_config_bool(k, v); return 0; } - return git_default_config(k, v); + return git_color_default_config(k, v); } -- cgit v1.3 From bc052d7f435f8f729127cc4790484865c1a974b9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 6 Mar 2008 12:26:14 -0800 Subject: Make 'unpack_trees()' take the index to work on as an argument This is just a very mechanical conversion, and makes everybody set it to '&the_index' before calling, but at least it makes it more explicit where we work with the index. The next stage would be to split that index usage up into a 'source' and a 'destination' index, so that we can unpack into a different index than we started out from. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-checkout.c | 6 ++++ builtin-commit.c | 1 + builtin-merge-recursive.c | 1 + builtin-read-tree.c | 1 + diff-lib.c | 2 ++ unpack-trees.c | 79 ++++++++++++++++++++++++----------------------- unpack-trees.h | 1 + 7 files changed, 52 insertions(+), 39 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-checkout.c b/builtin-checkout.c index 6b08016228..9bdb6233f0 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -152,6 +152,7 @@ static int reset_to_new(struct tree *tree, int quiet) { struct unpack_trees_options opts; struct tree_desc tree_desc; + memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; opts.update = 1; @@ -159,6 +160,7 @@ static int reset_to_new(struct tree *tree, int quiet) opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = !quiet; + opts.index = &the_index; parse_tree(tree); init_tree_desc(&tree_desc, tree->buffer, tree->size); if (unpack_trees(1, &tree_desc, &opts)) @@ -170,6 +172,7 @@ static void reset_clean_to_new(struct tree *tree, int quiet) { struct unpack_trees_options opts; struct tree_desc tree_desc; + memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; opts.skip_unmerged = 1; @@ -177,6 +180,7 @@ static void reset_clean_to_new(struct tree *tree, int quiet) opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = !quiet; + opts.index = &the_index; parse_tree(tree); init_tree_desc(&tree_desc, tree->buffer, tree->size); if (unpack_trees(1, &tree_desc, &opts)) @@ -224,8 +228,10 @@ static int merge_working_tree(struct checkout_opts *opts, struct tree_desc trees[2]; struct tree *tree; struct unpack_trees_options topts; + memset(&topts, 0, sizeof(topts)); topts.head_idx = -1; + topts.index = &the_index; refresh_cache(REFRESH_QUIET); diff --git a/builtin-commit.c b/builtin-commit.c index f49c22e642..38a542258a 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -198,6 +198,7 @@ static void create_base_index(void) opts.head_idx = 1; opts.index_only = 1; opts.merge = 1; + opts.index = &the_index; opts.fn = oneway_merge; tree = parse_tree_indirect(head_sha1); diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 6fe4102c0c..50b389623c 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -213,6 +213,7 @@ static int git_merge_trees(int index_only, opts.merge = 1; opts.head_idx = 2; opts.fn = threeway_merge; + opts.index = &the_index; init_tree_desc_from_tree(t+0, common); init_tree_desc_from_tree(t+1, head); diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 0138f5a917..d004e90431 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -102,6 +102,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; + opts.index = &the_index; git_config(git_default_config); diff --git a/diff-lib.c b/diff-lib.c index 4581b594d0..e359058d0b 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -734,6 +734,7 @@ int run_diff_index(struct rev_info *revs, int cached) opts.merge = 1; opts.fn = oneway_diff; opts.unpack_data = revs; + opts.index = &the_index; init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts)) @@ -787,6 +788,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) opts.merge = 1; opts.fn = oneway_diff; opts.unpack_data = &revs; + opts.index = &the_index; init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts)) diff --git a/unpack-trees.c b/unpack-trees.c index ee9be29374..cb8f847968 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1,3 +1,4 @@ +#define NO_THE_INDEX_COMPATIBILITY_MACROS #include "cache.h" #include "dir.h" #include "tree.h" @@ -7,10 +8,10 @@ #include "progress.h" #include "refs.h" -static inline void remove_entry(int remove) +static inline void remove_entry(int remove, struct unpack_trees_options *o) { if (remove >= 0) - remove_cache_entry_at(remove); + remove_index_entry_at(o->index, remove); } /* Unlink the last component and attempt to remove leading @@ -53,8 +54,8 @@ static void check_updates(struct unpack_trees_options *o) int i; if (o->update && o->verbose_update) { - for (total = cnt = 0; cnt < active_nr; cnt++) { - struct cache_entry *ce = active_cache[cnt]; + for (total = cnt = 0; cnt < o->index->cache_nr; cnt++) { + struct cache_entry *ce = o->index->cache[cnt]; if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) total++; } @@ -65,15 +66,15 @@ static void check_updates(struct unpack_trees_options *o) } *last_symlink = '\0'; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; + for (i = 0; i < o->index->cache_nr; i++) { + struct cache_entry *ce = o->index->cache[i]; if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) display_progress(progress, ++cnt); if (ce->ce_flags & CE_REMOVE) { if (o->update) unlink_entry(ce->name, last_symlink); - remove_cache_entry_at(i); + remove_index_entry_at(o->index, i); i--; continue; } @@ -105,7 +106,7 @@ static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_option if (o->skip_unmerged) { o->pos++; } else { - remove_entry(o->pos); + remove_entry(o->pos, o); } return 0; } @@ -242,9 +243,9 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas return call_unpack_fn(src, o, remove); n += o->merge; - remove_entry(remove); + remove_entry(remove, o); for (i = 0; i < n; i++) - add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK); + add_index_entry(o->index, src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK); return 0; } @@ -261,8 +262,8 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str /* Are we supposed to look at the index too? */ if (o->merge) { - while (o->pos < active_nr) { - struct cache_entry *ce = active_cache[o->pos]; + while (o->pos < o->index->cache_nr) { + struct cache_entry *ce = o->index->cache[o->pos]; int cmp = compare_entry(ce, info, p); if (cmp < 0) { if (unpack_index_entry(ce, o) < 0) @@ -277,7 +278,7 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str */ if (o->skip_unmerged) return mask; - remove_entry(o->pos); + remove_entry(o->pos, o); continue; } src[0] = ce; @@ -312,8 +313,8 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message) return error(message); return -1; } - discard_cache(); - read_cache(); + discard_index(o->index); + read_index(o->index); return -1; } @@ -349,8 +350,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options /* Any left-over entries in the index? */ if (o->merge) { - while (o->pos < active_nr) { - struct cache_entry *ce = active_cache[o->pos]; + while (o->pos < o->index->cache_nr) { + struct cache_entry *ce = o->index->cache[o->pos]; if (unpack_index_entry(ce, o) < 0) return unpack_failed(o, NULL); } @@ -395,7 +396,7 @@ static int verify_uptodate(struct cache_entry *ce, return 0; if (!lstat(ce->name, &st)) { - unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID); + unsigned changed = ie_match_stat(o->index, ce, &st, CE_MATCH_IGNORE_VALID); if (!changed) return 0; /* @@ -415,10 +416,10 @@ static int verify_uptodate(struct cache_entry *ce, error("Entry '%s' not uptodate. Cannot merge.", ce->name); } -static void invalidate_ce_path(struct cache_entry *ce) +static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o) { if (ce) - cache_tree_invalidate_path(active_cache_tree, ce->name); + cache_tree_invalidate_path(o->index->cache_tree, ce->name); } /* @@ -463,12 +464,12 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, * in that directory. */ namelen = strlen(ce->name); - pos = cache_name_pos(ce->name, namelen); + pos = index_name_pos(o->index, ce->name, namelen); if (0 <= pos) return cnt; /* we have it as nondirectory */ pos = -pos - 1; - for (i = pos; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; + for (i = pos; i < o->index->cache_nr; i++) { + struct cache_entry *ce = o->index->cache[i]; int len = ce_namelen(ce); if (len < namelen || strncmp(ce->name, ce->name, namelen) || @@ -566,9 +567,9 @@ static int verify_absent(struct cache_entry *ce, const char *action, * delete this path, which is in a subdirectory that * is being replaced with a blob. */ - cnt = cache_name_pos(ce->name, strlen(ce->name)); + cnt = index_name_pos(o->index, ce->name, strlen(ce->name)); if (0 <= cnt) { - struct cache_entry *ce = active_cache[cnt]; + struct cache_entry *ce = o->index->cache[cnt]; if (ce->ce_flags & CE_REMOVE) return 0; } @@ -597,17 +598,17 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, } else { if (verify_uptodate(old, o)) return -1; - invalidate_ce_path(old); + invalidate_ce_path(old, o); } } else { if (verify_absent(merge, "overwritten", o)) return -1; - invalidate_ce_path(merge); + invalidate_ce_path(merge, o); } merge->ce_flags &= ~CE_STAGEMASK; - add_cache_entry(merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + add_index_entry(o->index, merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); return 1; } @@ -621,14 +622,14 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, if (verify_absent(ce, "removed", o)) return -1; ce->ce_flags |= CE_REMOVE; - add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); - invalidate_ce_path(ce); + add_index_entry(o->index, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + invalidate_ce_path(ce, o); return 1; } static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o) { - add_cache_entry(ce, ADD_CACHE_OK_TO_ADD); + add_index_entry(o->index, ce, ADD_CACHE_OK_TO_ADD); return 1; } @@ -728,7 +729,7 @@ int threeway_merge(struct cache_entry **stages, /* #1 */ if (!head && !remote && any_anc_missing) { - remove_entry(remove); + remove_entry(remove, o); return 0; } @@ -762,7 +763,7 @@ int threeway_merge(struct cache_entry **stages, if ((head_deleted && remote_deleted) || (head_deleted && remote && remote_match) || (remote_deleted && head && head_match)) { - remove_entry(remove); + remove_entry(remove, o); if (index) return deleted_entry(index, index, o); else if (ce && !head_deleted) { @@ -788,7 +789,7 @@ int threeway_merge(struct cache_entry **stages, return -1; } - remove_entry(remove); + remove_entry(remove, o); o->nontrivial_merge = 1; /* #2, #3, #4, #6, #7, #9, #10, #11. */ @@ -853,7 +854,7 @@ int twoway_merge(struct cache_entry **src, } else if (oldtree && !newtree && same(current, oldtree)) { /* 10 or 11 */ - remove_entry(remove); + remove_entry(remove, o); return deleted_entry(oldtree, current, o); } else if (oldtree && newtree && @@ -863,7 +864,7 @@ int twoway_merge(struct cache_entry **src, } else { /* all other failures */ - remove_entry(remove); + remove_entry(remove, o); if (oldtree) return o->gently ? -1 : reject_merge(oldtree); if (current) @@ -875,7 +876,7 @@ int twoway_merge(struct cache_entry **src, } else if (newtree) return merged_entry(newtree, current, o); - remove_entry(remove); + remove_entry(remove, o); return deleted_entry(oldtree, current, o); } @@ -922,14 +923,14 @@ int oneway_merge(struct cache_entry **src, o->merge_size); if (!a) { - remove_entry(remove); + remove_entry(remove, o); return deleted_entry(old, old, o); } if (old && same(old, a)) { if (o->reset) { struct stat st; if (lstat(old->name, &st) || - ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID)) + ie_match_stat(o->index, old, &st, CE_MATCH_IGNORE_VALID)) old->ce_flags |= CE_UPDATE; } return keep_entry(old, o); diff --git a/unpack-trees.h b/unpack-trees.h index a2df544d04..65add1652f 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -28,6 +28,7 @@ struct unpack_trees_options { struct cache_entry *df_conflict_entry; void *unpack_data; + struct index_state *index; }; extern int unpack_trees(unsigned n, struct tree_desc *t, -- cgit v1.3 From 34110cd4e394e3f92c01a4709689b384c34645d8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 6 Mar 2008 18:12:28 -0800 Subject: Make 'unpack_trees()' have a separate source and destination index We will always unpack into our own internal index, but we will take the source from wherever specified, and we will optionally write the result to a specified index (optionally, because not everybody even _wants_ any result: the index diffing really wants to just walk the tree and index in parallel). This ends up removing a fair number more lines than it adds, for the simple reason that we can now skip all the crud that tried to be oh-so-careful about maintaining our position in the index as we were traversing and modifying it. Since we don't actually modify the source index any more, we can just update the 'o->pos' pointer without worrying about whether an index entry got removed or replaced or added to. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-checkout.c | 9 ++- builtin-commit.c | 3 +- builtin-merge-recursive.c | 3 +- builtin-read-tree.c | 24 +------- diff-lib.c | 49 +++------------ t/t1005-read-tree-reset.sh | 2 +- unpack-trees.c | 149 ++++++++++++++++++++++----------------------- unpack-trees.h | 16 ++--- 8 files changed, 102 insertions(+), 153 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-checkout.c b/builtin-checkout.c index 9bdb6233f0..7deb504837 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -160,7 +160,8 @@ static int reset_to_new(struct tree *tree, int quiet) opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = !quiet; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = &the_index; parse_tree(tree); init_tree_desc(&tree_desc, tree->buffer, tree->size); if (unpack_trees(1, &tree_desc, &opts)) @@ -180,7 +181,8 @@ static void reset_clean_to_new(struct tree *tree, int quiet) opts.merge = 1; opts.fn = oneway_merge; opts.verbose_update = !quiet; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = &the_index; parse_tree(tree); init_tree_desc(&tree_desc, tree->buffer, tree->size); if (unpack_trees(1, &tree_desc, &opts)) @@ -231,7 +233,8 @@ static int merge_working_tree(struct checkout_opts *opts, memset(&topts, 0, sizeof(topts)); topts.head_idx = -1; - topts.index = &the_index; + topts.src_index = &the_index; + topts.dst_index = &the_index; refresh_cache(REFRESH_QUIET); diff --git a/builtin-commit.c b/builtin-commit.c index 38a542258a..660a3458f7 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -198,7 +198,8 @@ static void create_base_index(void) opts.head_idx = 1; opts.index_only = 1; opts.merge = 1; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = &the_index; opts.fn = oneway_merge; tree = parse_tree_indirect(head_sha1); diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 50b389623c..fa02bb5a80 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -213,7 +213,8 @@ static int git_merge_trees(int index_only, opts.merge = 1; opts.head_idx = 2; opts.fn = threeway_merge; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = &the_index; init_tree_desc_from_tree(t+0, common); init_tree_desc_from_tree(t+1, head); diff --git a/builtin-read-tree.c b/builtin-read-tree.c index d004e90431..160456dad1 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -102,7 +102,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) memset(&opts, 0, sizeof(opts)); opts.head_idx = -1; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = &the_index; git_config(git_default_config); @@ -221,27 +222,6 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) if ((opts.dir && !opts.update)) die("--exclude-per-directory is meaningless unless -u"); - if (opts.prefix) { - int pfxlen = strlen(opts.prefix); - int pos; - if (opts.prefix[pfxlen-1] != '/') - die("prefix must end with /"); - if (stage != 2) - die("binding merge takes only one tree"); - pos = cache_name_pos(opts.prefix, pfxlen); - if (0 <= pos) - die("corrupt index file"); - pos = -pos-1; - if (pos < active_nr && - !strncmp(active_cache[pos]->name, opts.prefix, pfxlen)) - die("subdirectory '%s' already exists.", opts.prefix); - pos = cache_name_pos(opts.prefix, pfxlen-1); - if (0 <= pos) - die("file '%.*s' already exists.", - pfxlen-1, opts.prefix); - opts.pos = -1 - pos; - } - if (opts.merge) { if (stage < 2) die("just how do you expect me to merge %d trees?", stage-1); diff --git a/diff-lib.c b/diff-lib.c index e359058d0b..9520773f3b 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -600,8 +600,7 @@ static void mark_merge_entries(void) */ static void do_oneway_diff(struct unpack_trees_options *o, struct cache_entry *idx, - struct cache_entry *tree, - int idx_pos, int idx_nr) + struct cache_entry *tree) { struct rev_info *revs = o->unpack_data; int match_missing, cached; @@ -642,34 +641,6 @@ static void do_oneway_diff(struct unpack_trees_options *o, show_modified(revs, tree, idx, 1, cached, match_missing); } -/* - * Count how many index entries go with the first one - */ -static inline int count_skip(const struct cache_entry *src, int pos) -{ - int skip = 1; - - /* We can only have multiple entries if the first one is not stage-0 */ - if (ce_stage(src)) { - struct cache_entry **p = active_cache + pos; - int namelen = ce_namelen(src); - - for (;;) { - const struct cache_entry *ce; - pos++; - if (pos >= active_nr) - break; - ce = *++p; - if (ce_namelen(ce) != namelen) - break; - if (memcmp(ce->name, src->name, namelen)) - break; - skip++; - } - } - return skip; -} - /* * The unpack_trees() interface is designed for merging, so * the different source entries are designed primarily for @@ -685,18 +656,12 @@ static inline int count_skip(const struct cache_entry *src, int pos) * the fairly complex unpack_trees() semantic requirements, including * the skipping, the path matching, the type conflict cases etc. */ -static int oneway_diff(struct cache_entry **src, - struct unpack_trees_options *o, - int index_pos) +static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o) { - int skip = 0; struct cache_entry *idx = src[0]; struct cache_entry *tree = src[1]; struct rev_info *revs = o->unpack_data; - if (index_pos >= 0) - skip = count_skip(idx, index_pos); - /* * Unpack-trees generates a DF/conflict entry if * there was a directory in the index and a tree @@ -707,9 +672,9 @@ static int oneway_diff(struct cache_entry **src, tree = NULL; if (ce_path_match(idx ? idx : tree, revs->prune_data)) - do_oneway_diff(o, idx, tree, index_pos, skip); + do_oneway_diff(o, idx, tree); - return skip; + return 0; } int run_diff_index(struct rev_info *revs, int cached) @@ -734,7 +699,8 @@ int run_diff_index(struct rev_info *revs, int cached) opts.merge = 1; opts.fn = oneway_diff; opts.unpack_data = revs; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = NULL; init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts)) @@ -788,7 +754,8 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt) opts.merge = 1; opts.fn = oneway_diff; opts.unpack_data = &revs; - opts.index = &the_index; + opts.src_index = &the_index; + opts.dst_index = &the_index; init_tree_desc(&t, tree->buffer, tree->size); if (unpack_trees(1, &t, &opts)) diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh index f1b12167b8..8c4556408e 100755 --- a/t/t1005-read-tree-reset.sh +++ b/t/t1005-read-tree-reset.sh @@ -21,7 +21,7 @@ test_expect_success 'setup' ' git commit -m two ' -test_expect_failure 'reset should work' ' +test_expect_success 'reset should work' ' git read-tree -u --reset HEAD^ && git ls-files >actual && diff -u expect actual diff --git a/unpack-trees.c b/unpack-trees.c index cb8f847968..0cdf19817d 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -8,10 +8,18 @@ #include "progress.h" #include "refs.h" -static inline void remove_entry(int remove, struct unpack_trees_options *o) +static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce, + unsigned int set, unsigned int clear) { - if (remove >= 0) - remove_index_entry_at(o->index, remove); + unsigned int size = ce_size(ce); + struct cache_entry *new = xmalloc(size); + + clear |= CE_HASHED | CE_UNHASHED; + + memcpy(new, ce, size); + new->next = NULL; + new->ce_flags = (new->ce_flags & ~clear) | set; + add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK); } /* Unlink the last component and attempt to remove leading @@ -51,11 +59,12 @@ static void check_updates(struct unpack_trees_options *o) unsigned cnt = 0, total = 0; struct progress *progress = NULL; char last_symlink[PATH_MAX]; + struct index_state *index = &o->result; int i; if (o->update && o->verbose_update) { - for (total = cnt = 0; cnt < o->index->cache_nr; cnt++) { - struct cache_entry *ce = o->index->cache[cnt]; + for (total = cnt = 0; cnt < index->cache_nr; cnt++) { + struct cache_entry *ce = index->cache[cnt]; if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) total++; } @@ -66,15 +75,15 @@ static void check_updates(struct unpack_trees_options *o) } *last_symlink = '\0'; - for (i = 0; i < o->index->cache_nr; i++) { - struct cache_entry *ce = o->index->cache[i]; + for (i = 0; i < index->cache_nr; i++) { + struct cache_entry *ce = index->cache[i]; if (ce->ce_flags & (CE_UPDATE | CE_REMOVE)) display_progress(progress, ++cnt); if (ce->ce_flags & CE_REMOVE) { if (o->update) unlink_entry(ce->name, last_symlink); - remove_index_entry_at(o->index, i); + remove_index_entry_at(&o->result, i); i--; continue; } @@ -89,28 +98,27 @@ static void check_updates(struct unpack_trees_options *o) stop_progress(&progress); } -static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o, int remove) +static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_options *o) { - int ret = o->fn(src, o, remove); - if (ret > 0) { - o->pos += ret; + int ret = o->fn(src, o); + if (ret > 0) ret = 0; - } return ret; } static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o) { struct cache_entry *src[5] = { ce, }; + + o->pos++; if (ce_stage(ce)) { if (o->skip_unmerged) { - o->pos++; - } else { - remove_entry(o->pos, o); + add_entry(o, ce, 0, 0); + return 0; } return 0; } - return call_unpack_fn(src, o, o->pos); + return call_unpack_fn(src, o); } int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info) @@ -200,7 +208,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info, con } static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmask, struct cache_entry *src[5], - const struct name_entry *names, const struct traverse_info *info, int remove) + const struct name_entry *names, const struct traverse_info *info) { int i; struct unpack_trees_options *o = info->data; @@ -240,12 +248,11 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas } if (o->merge) - return call_unpack_fn(src, o, remove); + return call_unpack_fn(src, o); n += o->merge; - remove_entry(remove, o); for (i = 0; i < n; i++) - add_index_entry(o->index, src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK); + add_entry(o, src[i], 0, 0); return 0; } @@ -253,7 +260,6 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str { struct cache_entry *src[5] = { NULL, }; struct unpack_trees_options *o = info->data; - int remove = -1; const struct name_entry *p = names; /* Find first entry with a real name (we could use "mask" too) */ @@ -262,8 +268,8 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str /* Are we supposed to look at the index too? */ if (o->merge) { - while (o->pos < o->index->cache_nr) { - struct cache_entry *ce = o->index->cache[o->pos]; + while (o->pos < o->src_index->cache_nr) { + struct cache_entry *ce = o->src_index->cache[o->pos]; int cmp = compare_entry(ce, info, p); if (cmp < 0) { if (unpack_index_entry(ce, o) < 0) @@ -271,24 +277,25 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str continue; } if (!cmp) { + o->pos++; if (ce_stage(ce)) { /* * If we skip unmerged index entries, we'll skip this * entry *and* the tree entries associated with it! */ - if (o->skip_unmerged) + if (o->skip_unmerged) { + add_entry(o, ce, 0, 0); return mask; - remove_entry(o->pos, o); + } continue; } src[0] = ce; - remove = o->pos; } break; } } - if (unpack_nondirectories(n, mask, dirmask, src, names, info, remove) < 0) + if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0) return -1; /* Now handle any directories.. */ @@ -313,8 +320,6 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message) return error(message); return -1; } - discard_index(o->index); - read_index(o->index); return -1; } @@ -330,6 +335,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options state.quiet = 1; state.refresh_cache = 1; + memset(&o->result, 0, sizeof(o->result)); o->merge_size = len; if (!dfc) @@ -350,8 +356,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options /* Any left-over entries in the index? */ if (o->merge) { - while (o->pos < o->index->cache_nr) { - struct cache_entry *ce = o->index->cache[o->pos]; + while (o->pos < o->src_index->cache_nr) { + struct cache_entry *ce = o->src_index->cache[o->pos]; if (unpack_index_entry(ce, o) < 0) return unpack_failed(o, NULL); } @@ -360,7 +366,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options if (o->trivial_merges_only && o->nontrivial_merge) return unpack_failed(o, "Merge requires file-level merging"); + o->src_index = NULL; check_updates(o); + if (o->dst_index) + *o->dst_index = o->result; return 0; } @@ -396,7 +405,7 @@ static int verify_uptodate(struct cache_entry *ce, return 0; if (!lstat(ce->name, &st)) { - unsigned changed = ie_match_stat(o->index, ce, &st, CE_MATCH_IGNORE_VALID); + unsigned changed = ie_match_stat(o->src_index, ce, &st, CE_MATCH_IGNORE_VALID); if (!changed) return 0; /* @@ -419,7 +428,7 @@ static int verify_uptodate(struct cache_entry *ce, static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o) { if (ce) - cache_tree_invalidate_path(o->index->cache_tree, ce->name); + cache_tree_invalidate_path(o->src_index->cache_tree, ce->name); } /* @@ -464,12 +473,12 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, * in that directory. */ namelen = strlen(ce->name); - pos = index_name_pos(o->index, ce->name, namelen); + pos = index_name_pos(o->src_index, ce->name, namelen); if (0 <= pos) return cnt; /* we have it as nondirectory */ pos = -pos - 1; - for (i = pos; i < o->index->cache_nr; i++) { - struct cache_entry *ce = o->index->cache[i]; + for (i = pos; i < o->src_index->cache_nr; i++) { + struct cache_entry *ce = o->src_index->cache[i]; int len = ce_namelen(ce); if (len < namelen || strncmp(ce->name, ce->name, namelen) || @@ -481,7 +490,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action, if (!ce_stage(ce)) { if (verify_uptodate(ce, o)) return -1; - ce->ce_flags |= CE_REMOVE; + add_entry(o, ce, CE_REMOVE, 0); } cnt++; } @@ -567,9 +576,9 @@ static int verify_absent(struct cache_entry *ce, const char *action, * delete this path, which is in a subdirectory that * is being replaced with a blob. */ - cnt = index_name_pos(o->index, ce->name, strlen(ce->name)); + cnt = index_name_pos(&o->result, ce->name, strlen(ce->name)); if (0 <= cnt) { - struct cache_entry *ce = o->index->cache[cnt]; + struct cache_entry *ce = o->result.cache[cnt]; if (ce->ce_flags & CE_REMOVE) return 0; } @@ -584,7 +593,6 @@ static int verify_absent(struct cache_entry *ce, const char *action, static int merged_entry(struct cache_entry *merge, struct cache_entry *old, struct unpack_trees_options *o) { - merge->ce_flags |= CE_UPDATE; if (old) { /* * See if we can re-use the old CE directly? @@ -607,29 +615,29 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old, invalidate_ce_path(merge, o); } - merge->ce_flags &= ~CE_STAGEMASK; - add_index_entry(o->index, merge, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + add_entry(o, merge, CE_UPDATE, CE_STAGEMASK); return 1; } static int deleted_entry(struct cache_entry *ce, struct cache_entry *old, struct unpack_trees_options *o) { - if (old) { - if (verify_uptodate(old, o)) - return -1; - } else + /* Did it exist in the index? */ + if (!old) { if (verify_absent(ce, "removed", o)) return -1; - ce->ce_flags |= CE_REMOVE; - add_index_entry(o->index, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); + return 0; + } + if (verify_uptodate(old, o)) + return -1; + add_entry(o, ce, CE_REMOVE, 0); invalidate_ce_path(ce, o); return 1; } static int keep_entry(struct cache_entry *ce, struct unpack_trees_options *o) { - add_index_entry(o->index, ce, ADD_CACHE_OK_TO_ADD); + add_entry(o, ce, 0, 0); return 1; } @@ -649,9 +657,7 @@ static void show_stage_entry(FILE *o, } #endif -int threeway_merge(struct cache_entry **stages, - struct unpack_trees_options *o, - int remove) +int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o) { struct cache_entry *index; struct cache_entry *head; @@ -728,10 +734,8 @@ int threeway_merge(struct cache_entry **stages, } /* #1 */ - if (!head && !remote && any_anc_missing) { - remove_entry(remove, o); + if (!head && !remote && any_anc_missing) return 0; - } /* Under the new "aggressive" rule, we resolve mostly trivial * cases that we historically had git-merge-one-file resolve. @@ -763,10 +767,9 @@ int threeway_merge(struct cache_entry **stages, if ((head_deleted && remote_deleted) || (head_deleted && remote && remote_match) || (remote_deleted && head && head_match)) { - remove_entry(remove, o); if (index) return deleted_entry(index, index, o); - else if (ce && !head_deleted) { + if (ce && !head_deleted) { if (verify_absent(ce, "removed", o)) return -1; } @@ -789,7 +792,6 @@ int threeway_merge(struct cache_entry **stages, return -1; } - remove_entry(remove, o); o->nontrivial_merge = 1; /* #2, #3, #4, #6, #7, #9, #10, #11. */ @@ -824,9 +826,7 @@ int threeway_merge(struct cache_entry **stages, * "carry forward" rule, please see . * */ -int twoway_merge(struct cache_entry **src, - struct unpack_trees_options *o, - int remove) +int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o) { struct cache_entry *current = src[0]; struct cache_entry *oldtree = src[1]; @@ -854,7 +854,6 @@ int twoway_merge(struct cache_entry **src, } else if (oldtree && !newtree && same(current, oldtree)) { /* 10 or 11 */ - remove_entry(remove, o); return deleted_entry(oldtree, current, o); } else if (oldtree && newtree && @@ -864,7 +863,6 @@ int twoway_merge(struct cache_entry **src, } else { /* all other failures */ - remove_entry(remove, o); if (oldtree) return o->gently ? -1 : reject_merge(oldtree); if (current) @@ -876,7 +874,6 @@ int twoway_merge(struct cache_entry **src, } else if (newtree) return merged_entry(newtree, current, o); - remove_entry(remove, o); return deleted_entry(oldtree, current, o); } @@ -887,8 +884,7 @@ int twoway_merge(struct cache_entry **src, * stage0 does not have anything there. */ int bind_merge(struct cache_entry **src, - struct unpack_trees_options *o, - int remove) + struct unpack_trees_options *o) { struct cache_entry *old = src[0]; struct cache_entry *a = src[1]; @@ -898,7 +894,7 @@ int bind_merge(struct cache_entry **src, o->merge_size); if (a && old) return o->gently ? -1 : - error("Entry '%s' overlaps. Cannot bind.", a->name); + error("Entry '%s' overlaps with '%s'. Cannot bind.", a->name, old->name); if (!a) return keep_entry(old, o); else @@ -911,9 +907,7 @@ int bind_merge(struct cache_entry **src, * The rule is: * - take the stat information from stage0, take the data from stage1 */ -int oneway_merge(struct cache_entry **src, - struct unpack_trees_options *o, - int remove) +int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o) { struct cache_entry *old = src[0]; struct cache_entry *a = src[1]; @@ -922,18 +916,19 @@ int oneway_merge(struct cache_entry **src, return error("Cannot do a oneway merge of %d trees", o->merge_size); - if (!a) { - remove_entry(remove, o); + if (!a) return deleted_entry(old, old, o); - } + if (old && same(old, a)) { + int update = 0; if (o->reset) { struct stat st; if (lstat(old->name, &st) || - ie_match_stat(o->index, old, &st, CE_MATCH_IGNORE_VALID)) - old->ce_flags |= CE_UPDATE; + ie_match_stat(o->src_index, old, &st, CE_MATCH_IGNORE_VALID)) + update |= CE_UPDATE; } - return keep_entry(old, o); + add_entry(o, old, update, 0); + return 0; } return merged_entry(a, old, o); } diff --git a/unpack-trees.h b/unpack-trees.h index 65add1652f..e8abbcd037 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -4,8 +4,7 @@ struct unpack_trees_options; typedef int (*merge_fn_t)(struct cache_entry **src, - struct unpack_trees_options *options, - int remove); + struct unpack_trees_options *options); struct unpack_trees_options { int reset; @@ -28,15 +27,18 @@ struct unpack_trees_options { struct cache_entry *df_conflict_entry; void *unpack_data; - struct index_state *index; + + struct index_state *dst_index; + const struct index_state *src_index; + struct index_state result; }; extern int unpack_trees(unsigned n, struct tree_desc *t, struct unpack_trees_options *options); -int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o, int); -int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o, int); -int bind_merge(struct cache_entry **src, struct unpack_trees_options *o, int); -int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o, int); +int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o); +int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o); +int bind_merge(struct cache_entry **src, struct unpack_trees_options *o); +int oneway_merge(struct cache_entry **src, struct unpack_trees_options *o); #endif -- cgit v1.3 From 4da45bef56e1547eb6525015ada0fdfc01d8295b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 7 Apr 2008 17:11:34 -0700 Subject: log: teach "terminator" vs "separator" mode to "--pretty=format" This attached patch introduces a single bit "use_terminator" in "struct rev_info", which is normally false (i.e. most formats use separator semantics) but by flipping it to true, you can ask for terminator semantics just like oneline format does. The function get_commit_format(), which is what parses "--pretty=" option, now takes a pointer to "struct rev_info" and updates its commit_format and use_terminator fields. It used to return the value of type "enum cmit_fmt", but all the callers assigned it to rev->commit_format. There are only two cases the code turns use_terminator on. Obviously, the traditional oneline format (--pretty=oneline) is one of them, and the new case is --pretty=tformat:... that acts like --pretty=format:... but flips the bit on. With this, "--pretty=tformat:%H %s" acts like --pretty=oneline. Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- builtin-log.c | 3 ++- commit.h | 3 ++- log-tree.c | 4 ++-- pretty.c | 57 ++++++++++++++++++++++++++++++++------------------------ revision.c | 2 +- revision.h | 3 ++- 7 files changed, 43 insertions(+), 31 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 660a3458f7..8bf35033e4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -810,7 +810,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) rev.verbose_header = 1; rev.show_root_diff = 1; - rev.commit_format = get_commit_format("format:%h: %s"); + get_commit_format("format:%h: %s", &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; rev.diffopt.rename_limit = 100; diff --git a/builtin-log.c b/builtin-log.c index 5c00725f03..1670d0b334 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -56,7 +56,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, rev->abbrev = DEFAULT_ABBREV; rev->commit_format = CMIT_FMT_DEFAULT; if (fmt_pretty) - rev->commit_format = get_commit_format(fmt_pretty); + get_commit_format(fmt_pretty, rev); rev->verbose_header = 1; DIFF_OPT_SET(&rev->diffopt, RECURSIVE); rev->show_root_diff = default_show_root; @@ -400,6 +400,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) * allow us to set a different default. */ rev.commit_format = CMIT_FMT_ONELINE; + rev.use_terminator = 1; rev.always_show_header = 1; /* diff --git a/commit.h b/commit.h index 2f63bc8b2f..2d94d4148e 100644 --- a/commit.h +++ b/commit.h @@ -63,7 +63,8 @@ enum cmit_fmt { }; extern int non_ascii(int); -extern enum cmit_fmt get_commit_format(const char *arg); +struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ +extern void get_commit_format(const char *arg, struct rev_info *); extern void format_commit_message(const struct commit *commit, const void *format, struct strbuf *sb); extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*, diff --git a/log-tree.c b/log-tree.c index 9d54061601..8f5436b747 100644 --- a/log-tree.c +++ b/log-tree.c @@ -249,9 +249,9 @@ void show_log(struct rev_info *opt, const char *sep) * not have an empty line between entries. */ extra = ""; - if (*sep != '\n' && opt->commit_format == CMIT_FMT_ONELINE) + if (*sep != '\n' && opt->use_terminator) extra = "\n"; - if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE) + if (opt->shown_one && !opt->use_terminator) putchar(opt->diffopt.line_termination); opt->shown_one = 1; diff --git a/pretty.c b/pretty.c index 6c04176cb8..687293224c 100644 --- a/pretty.c +++ b/pretty.c @@ -4,40 +4,49 @@ #include "diff.h" #include "revision.h" -static struct cmt_fmt_map { - const char *n; - size_t cmp_len; - enum cmit_fmt v; -} cmt_fmts[] = { - { "raw", 1, CMIT_FMT_RAW }, - { "medium", 1, CMIT_FMT_MEDIUM }, - { "short", 1, CMIT_FMT_SHORT }, - { "email", 1, CMIT_FMT_EMAIL }, - { "full", 5, CMIT_FMT_FULL }, - { "fuller", 5, CMIT_FMT_FULLER }, - { "oneline", 1, CMIT_FMT_ONELINE }, - { "format:", 7, CMIT_FMT_USERFORMAT}, -}; - static char *user_format; -enum cmit_fmt get_commit_format(const char *arg) +void get_commit_format(const char *arg, struct rev_info *rev) { int i; - - if (!arg || !*arg) - return CMIT_FMT_DEFAULT; + static struct cmt_fmt_map { + const char *n; + size_t cmp_len; + enum cmit_fmt v; + } cmt_fmts[] = { + { "raw", 1, CMIT_FMT_RAW }, + { "medium", 1, CMIT_FMT_MEDIUM }, + { "short", 1, CMIT_FMT_SHORT }, + { "email", 1, CMIT_FMT_EMAIL }, + { "full", 5, CMIT_FMT_FULL }, + { "fuller", 5, CMIT_FMT_FULLER }, + { "oneline", 1, CMIT_FMT_ONELINE }, + }; + + rev->use_terminator = 0; + if (!arg || !*arg) { + rev->commit_format = CMIT_FMT_DEFAULT; + return; + } if (*arg == '=') arg++; - if (!prefixcmp(arg, "format:")) { + if (!prefixcmp(arg, "format:") || !prefixcmp(arg, "tformat:")) { + const char *cp = strchr(arg, ':') + 1; free(user_format); - user_format = xstrdup(arg + 7); - return CMIT_FMT_USERFORMAT; + user_format = xstrdup(cp); + if (arg[0] == 't') + rev->use_terminator = 1; + rev->commit_format = CMIT_FMT_USERFORMAT; + return; } for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) { if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) && - !strncmp(arg, cmt_fmts[i].n, strlen(arg))) - return cmt_fmts[i].v; + !strncmp(arg, cmt_fmts[i].n, strlen(arg))) { + if (cmt_fmts[i].v == CMIT_FMT_ONELINE) + rev->use_terminator = 1; + rev->commit_format = cmt_fmts[i].v; + return; + } } die("invalid --pretty format: %s", arg); diff --git a/revision.c b/revision.c index 196fedc9d1..781c503dfc 100644 --- a/revision.c +++ b/revision.c @@ -1198,7 +1198,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch } if (!prefixcmp(arg, "--pretty")) { revs->verbose_header = 1; - revs->commit_format = get_commit_format(arg+8); + get_commit_format(arg+8, revs); continue; } if (!strcmp(arg, "--root")) { diff --git a/revision.h b/revision.h index c8b3b948ec..31217f8c67 100644 --- a/revision.h +++ b/revision.h @@ -64,7 +64,8 @@ struct rev_info { /* Format info */ unsigned int shown_one:1, - abbrev_commit:1; + abbrev_commit:1, + use_terminator:1; enum date_mode date_mode; const char **ignore_packed; /* pretend objects in these are unpacked */ -- cgit v1.3 From d4ba07cac576e87fd194df0853ed523af6c58af1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 10 Apr 2008 13:33:09 +0200 Subject: Document option --only of git commit Its documentation was removed by 6c96753 (Documentation/git-commit: rewrite to make it more end-user friendly, 2006-12-08), even though it is referenced from a few places, including builtin-commit.c (as part of the commentary in the commit message template). Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Documentation/git-commit.txt | 11 +++++++++++ builtin-commit.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index c3725b2ed9..488d873f43 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -139,6 +139,17 @@ but can be used to amend a merge commit. as well. This is usually not what you want unless you are concluding a conflicted merge. +-o|--only:: + Make a commit only from the paths specified on the + command line, disregarding any contents that have been + staged so far. This is the default mode of operation of + 'git commit' if any paths are given on the command line, + in which case this option can be omitted. + If this option is specified together with '--amend', then + no paths need be specified, which can be used to amend + the last commit without committing changes that have + already been staged. + -u|--untracked-files:: Show all untracked files, also those in uninteresting directories, in the "Untracked files:" section of commit diff --git a/builtin-commit.c b/builtin-commit.c index 45232a11c4..a228a43f75 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -97,7 +97,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('a', "all", &all, "commit all changed files"), OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"), OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"), - OPT_BOOLEAN('o', "only", &only, ""), + OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"), -- cgit v1.3 From 3c5283f8b19aaba3a6105fa486cabe4d0ca48009 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Thu, 10 Apr 2008 13:33:08 +0200 Subject: builtin-commit.c: Remove a redundant assignment. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- builtin-commit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 660a3458f7..e3adfdf6d4 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -745,10 +745,8 @@ static int parse_and_validate_options(int argc, const char *argv[], die("No paths with --include/--only does not make sense."); if (argc == 0 && only && amend) only_include_assumed = "Clever... amending the last one with dirty index."; - if (argc > 0 && !also && !only) { + if (argc > 0 && !also && !only) only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths..."; - also = 0; - } if (!cleanup_arg || !strcmp(cleanup_arg, "default")) cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE; else if (!strcmp(cleanup_arg, "verbatim")) -- cgit v1.3 From 362b0dd523f5162e7c55c76b5d0af7ad830e0e83 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 26 Apr 2008 19:43:20 -0500 Subject: Remove 'header' from --signoff option description Signed-off-by: Dan McGee Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index a228a43f75..a2da314ac6 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -89,7 +89,7 @@ static struct option builtin_commit_options[] = { OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m), OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "), OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"), - OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"), + OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"), OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"), OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"), -- cgit v1.3 From a45d46ba72a8be16eeb30f608620bac7d9296803 Mon Sep 17 00:00:00 2001 From: Santi Béjar Date: Sun, 4 May 2008 18:04:49 +0200 Subject: Preparation to call determine_author_info from prepare_to_commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorder functions definitions such that determine_author_info is defined before prepare_to_commit. No code changes. Signed-off-by: Santi Béjar Signed-off-by: Junio C Hamano --- builtin-commit.c | 78 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 256181a68b..a37d8c35c0 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -395,6 +395,45 @@ static int is_a_merge(const unsigned char *sha1) static const char sign_off_header[] = "Signed-off-by: "; +static void determine_author_info(struct strbuf *sb) +{ + char *name, *email, *date; + + name = getenv("GIT_AUTHOR_NAME"); + email = getenv("GIT_AUTHOR_EMAIL"); + date = getenv("GIT_AUTHOR_DATE"); + + if (use_message) { + const char *a, *lb, *rb, *eol; + + a = strstr(use_message_buffer, "\nauthor "); + if (!a) + die("invalid commit: %s", use_message); + + lb = strstr(a + 8, " <"); + rb = strstr(a + 8, "> "); + eol = strchr(a + 8, '\n'); + if (!lb || !rb || !eol) + die("invalid commit: %s", use_message); + + name = xstrndup(a + 8, lb - (a + 8)); + email = xstrndup(lb + 2, rb - (lb + 2)); + date = xstrndup(rb + 2, eol - (rb + 2)); + } + + if (force_author) { + const char *lb = strstr(force_author, " <"); + const char *rb = strchr(force_author, '>'); + + if (!lb || !rb) + die("malformed --author parameter"); + name = xstrndup(force_author, lb - force_author); + email = xstrndup(lb + 2, rb - (lb + 2)); + } + + strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, IDENT_ERROR_ON_NO_NAME)); +} + static int prepare_to_commit(const char *index_file, const char *prefix) { struct stat statbuf; @@ -622,45 +661,6 @@ static int message_is_empty(struct strbuf *sb, int start) return 1; } -static void determine_author_info(struct strbuf *sb) -{ - char *name, *email, *date; - - name = getenv("GIT_AUTHOR_NAME"); - email = getenv("GIT_AUTHOR_EMAIL"); - date = getenv("GIT_AUTHOR_DATE"); - - if (use_message) { - const char *a, *lb, *rb, *eol; - - a = strstr(use_message_buffer, "\nauthor "); - if (!a) - die("invalid commit: %s", use_message); - - lb = strstr(a + 8, " <"); - rb = strstr(a + 8, "> "); - eol = strchr(a + 8, '\n'); - if (!lb || !rb || !eol) - die("invalid commit: %s", use_message); - - name = xstrndup(a + 8, lb - (a + 8)); - email = xstrndup(lb + 2, rb - (lb + 2)); - date = xstrndup(rb + 2, eol - (rb + 2)); - } - - if (force_author) { - const char *lb = strstr(force_author, " <"); - const char *rb = strchr(force_author, '>'); - - if (!lb || !rb) - die("malformed --author parameter"); - name = xstrndup(force_author, lb - force_author); - email = xstrndup(lb + 2, rb - (lb + 2)); - } - - strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, IDENT_ERROR_ON_NO_NAME)); -} - static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[]) { -- cgit v1.3 From e83dbe802f24e017f2e3889272a70793c064d984 Mon Sep 17 00:00:00 2001 From: Santi Béjar Date: Sun, 4 May 2008 18:04:50 +0200 Subject: commit: Show author if different from committer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That would help reassure anybody while committing other's changes. Signed-off-by: Santi Béjar Signed-off-by: Junio C Hamano --- builtin-commit.c | 26 +++++++++++++++++++++++--- t/t7502-commit.sh | 12 ++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index a37d8c35c0..4e51b9e354 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -47,6 +47,7 @@ static enum { static char *logfile, *force_author, *template_file; static char *edit_message, *use_message; +static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; static int quiet, verbose, untracked_files, no_verify, allow_empty; /* @@ -395,7 +396,7 @@ static int is_a_merge(const unsigned char *sha1) static const char sign_off_header[] = "Signed-off-by: "; -static void determine_author_info(struct strbuf *sb) +static void determine_author_info(void) { char *name, *email, *date; @@ -431,7 +432,9 @@ static void determine_author_info(struct strbuf *sb) email = xstrndup(lb + 2, rb - (lb + 2)); } - strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, IDENT_ERROR_ON_NO_NAME)); + author_name = name; + author_email = email; + author_date = date; } static int prepare_to_commit(const char *index_file, const char *prefix) @@ -522,7 +525,12 @@ static int prepare_to_commit(const char *index_file, const char *prefix) strbuf_release(&sb); + determine_author_info(); + if (use_editor) { + char *author_ident; + const char *committer_ident; + if (in_merge) fprintf(fp, "#\n" @@ -545,6 +553,17 @@ static int prepare_to_commit(const char *index_file, const char *prefix) 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, + "#\n" + "# Author: %s\n" + "#\n", + author_ident); + free(author_ident); + saved_color_setting = wt_status_use_color; wt_status_use_color = 0; commitable = run_status(fp, index_file, prefix, 1); @@ -920,7 +939,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1)); } - determine_author_info(&sb); + strbuf_addf(&sb, "author %s\n", + fmt_ident(author_name, author_email, author_date, IDENT_ERROR_ON_NO_NAME)); strbuf_addf(&sb, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); if (!is_encoding_utf8(git_commit_encoding)) strbuf_addf(&sb, "encoding %s\n", git_commit_encoding); diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 284c941247..0b1db406a7 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -154,6 +154,18 @@ test_expect_success 'cleanup commit messages (strip,-F,-e)' ' ' +echo "# +# Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> +#" >> expect + +test_expect_success 'author different from committer' ' + + echo >>negative && + git commit -e -m "sample" + head -n 7 .git/COMMIT_EDITMSG >actual && + test_cmp expect actual +' + pwd=`pwd` cat >> .git/FAKE_EDITOR << EOF #! /bin/sh -- cgit v1.3 From bb1ae3f6fff19b0a1ab1bb6a815d26d39b9f15e6 Mon Sep 17 00:00:00 2001 From: Santi Béjar Date: Sun, 4 May 2008 18:04:51 +0200 Subject: commit: Show committer if automatic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To warn the user in case he/she might be using an unintended committer identity. Signed-off-by: Santi Béjar Signed-off-by: Junio C Hamano --- builtin-commit.c | 19 ++++++++++++++++--- cache.h | 1 + config.c | 4 ++++ environment.c | 1 + ident.c | 3 +++ t/t7502-commit.sh | 15 +++++++++++++++ 6 files changed, 40 insertions(+), 3 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 4e51b9e354..a113eb0272 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -446,6 +446,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) 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; @@ -527,6 +528,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix) 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; @@ -558,12 +561,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix) getenv("GIT_COMMITTER_EMAIL")); if (strcmp(author_ident, committer_ident)) fprintf(fp, - "#\n" - "# Author: %s\n" - "#\n", + "%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); diff --git a/cache.h b/cache.h index d5d5dad146..327e5eacd3 100644 --- a/cache.h +++ b/cache.h @@ -719,6 +719,7 @@ extern int config_error_nonbool(const char *); #define MAX_GITNAME (1000) extern char git_default_email[MAX_GITNAME]; extern char git_default_name[MAX_GITNAME]; +extern int user_ident_explicitly_given; extern const char *git_commit_encoding; extern const char *git_log_output_encoding; diff --git a/config.c b/config.c index b0ada515b9..3bc4c7ed59 100644 --- a/config.c +++ b/config.c @@ -443,6 +443,8 @@ int git_default_config(const char *var, const char *value) if (!value) return config_error_nonbool(var); strlcpy(git_default_name, value, sizeof(git_default_name)); + if (git_default_email[0]) + user_ident_explicitly_given = 1; return 0; } @@ -450,6 +452,8 @@ int git_default_config(const char *var, const char *value) if (!value) return config_error_nonbool(var); strlcpy(git_default_email, value, sizeof(git_default_email)); + if (git_default_name[0]) + user_ident_explicitly_given = 1; return 0; } diff --git a/environment.c b/environment.c index fcd1ee5ef8..1b80036ca5 100644 --- a/environment.c +++ b/environment.c @@ -11,6 +11,7 @@ char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; +int user_ident_explicitly_given; int trust_executable_bit = 1; int quote_path_fully = 1; int has_symlinks = 1; diff --git a/ident.c b/ident.c index ed44a5345a..b35504a8d2 100644 --- a/ident.c +++ b/ident.c @@ -250,6 +250,9 @@ const char *git_author_info(int flag) const char *git_committer_info(int flag) { + if (getenv("GIT_COMMITTER_NAME") && + getenv("GIT_COMMITTER_EMAIL")) + user_ident_explicitly_given = 1; return fmt_ident(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"), getenv("GIT_COMMITTER_DATE"), diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 0b1db406a7..018060c60f 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -166,6 +166,21 @@ test_expect_success 'author different from committer' ' test_cmp expect actual ' +sed -i '$d' expect +echo "# Committer: +#" >> expect +unset GIT_COMMITTER_EMAIL +unset GIT_COMMITTER_NAME + +test_expect_success 'committer is automatic' ' + + echo >>negative && + git commit -e -m "sample" + head -n 8 .git/COMMIT_EDITMSG | \ + sed "s/^# Committer: .*/# Committer:/" >actual && + test_cmp expect actual +' + pwd=`pwd` cat >> .git/FAKE_EDITOR << EOF #! /bin/sh -- cgit v1.3 From d177cab0480f9fa172103071203fed1bff95f5c2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 9 May 2008 09:11:43 -0700 Subject: Avoid some unnecessary lstat() calls The commit sequence used to do if (file_exists(p->path)) add_file_to_cache(p->path, 0); where both "file_exists()" and "add_file_to_cache()" needed to do a lstat() on the path to do their work. This cuts down 'lstat()' calls for the partial commit case by two for each path we know about (because we do this twice per path). Just move the lstat() to the caller instead (that's all that "file_exists()" really does), and pass the stat information down to the add_to_cache() function. This essentially makes 'add_to_index()' the core function that adds a path to the index, getting the index pointer, the pathname and the stat information as arguments. There are then shorthand helper functions that use this core function: - 'add_to_cache()' is just 'add_to_index()' with the default index - 'add_file_to_cache/index()' is the same, but does the lstat() call itself, so you can pass just the pathname if you don't already have the stat information available. So old users of the 'add_file_to_xyzzy()' are essentially left unchanged, and this just exposes the more generic helper function that can take existing stat information into account. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-commit.c | 6 ++++-- cache.h | 2 ++ read-cache.c | 29 +++++++++++++++++------------ 3 files changed, 23 insertions(+), 14 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 256181a68b..6433f86cbb 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -175,9 +175,11 @@ static void add_remove_files(struct path_list *list) { int i; for (i = 0; i < list->nr; i++) { + struct stat st; struct path_list_item *p = &(list->items[i]); - if (file_exists(p->path)) - add_file_to_cache(p->path, 0); + + if (!lstat(p->path, &st)) + add_to_cache(p->path, &st, 0); else remove_file_from_cache(p->path); } diff --git a/cache.h b/cache.h index 80a8842db4..4803b032ec 100644 --- a/cache.h +++ b/cache.h @@ -261,6 +261,7 @@ static inline void remove_name_hash(struct cache_entry *ce) #define add_cache_entry(ce, option) add_index_entry(&the_index, (ce), (option)) #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos)) #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path)) +#define add_to_cache(path, st, verbose) add_to_index(&the_index, (path), (st), (verbose)) #define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose)) #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL) #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options)) @@ -365,6 +366,7 @@ extern int add_index_entry(struct index_state *, struct cache_entry *ce, int opt extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really); extern int remove_index_entry_at(struct index_state *, int pos); extern int remove_file_from_index(struct index_state *, const char *path); +extern int add_to_index(struct index_state *, const char *path, struct stat *, int verbose); extern int add_file_to_index(struct index_state *, const char *path, int verbose); extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh); extern int ce_same_name(struct cache_entry *a, struct cache_entry *b); diff --git a/read-cache.c b/read-cache.c index 4525f8a5ac..0382804e76 100644 --- a/read-cache.c +++ b/read-cache.c @@ -462,21 +462,18 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_ return new; } -int add_file_to_index(struct index_state *istate, const char *path, int verbose) +int add_to_index(struct index_state *istate, const char *path, struct stat *st, int verbose) { int size, namelen; - struct stat st; + mode_t st_mode = st->st_mode; struct cache_entry *ce, *alias; unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY; - if (lstat(path, &st)) - die("%s: unable to stat (%s)", path, strerror(errno)); - - if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode)) + if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode)) die("%s: can only add regular files, symbolic links or git-directories", path); namelen = strlen(path); - if (S_ISDIR(st.st_mode)) { + if (S_ISDIR(st_mode)) { while (namelen && path[namelen-1] == '/') namelen--; } @@ -484,10 +481,10 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) ce = xcalloc(1, size); memcpy(ce->name, path, namelen); ce->ce_flags = namelen; - fill_stat_cache_info(ce, &st); + fill_stat_cache_info(ce, st); if (trust_executable_bit && has_symlinks) - ce->ce_mode = create_ce_mode(st.st_mode); + ce->ce_mode = create_ce_mode(st_mode); else { /* If there is an existing entry, pick the mode bits and type * from it, otherwise assume unexecutable regular file. @@ -496,18 +493,18 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) int pos = index_name_pos_also_unmerged(istate, path, namelen); ent = (0 <= pos) ? istate->cache[pos] : NULL; - ce->ce_mode = ce_mode_from_stat(ent, st.st_mode); + ce->ce_mode = ce_mode_from_stat(ent, st_mode); } alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case); - if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, &st, ce_option)) { + if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) { /* Nothing changed, really */ free(ce); ce_mark_uptodate(alias); alias->ce_flags |= CE_ADDED; return 0; } - if (index_path(ce->sha1, path, &st, 1)) + if (index_path(ce->sha1, path, st, 1)) die("unable to index file %s", path); if (ignore_case && alias && different_name(ce, alias)) ce = create_alias_ce(ce, alias); @@ -519,6 +516,14 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) return 0; } +int add_file_to_index(struct index_state *istate, const char *path, int verbose) +{ + struct stat st; + if (lstat(path, &st)) + die("%s: unable to stat (%s)", path, strerror(errno)); + return add_to_index(istate, path, &st, verbose); +} + struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh) -- cgit v1.3 From e1645901ed72f82ae55139bbae01eac1bf5899c9 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 9 May 2008 22:42:55 +0530 Subject: builtin-commit.c: add -u as short name for --untracked-files This makes the C code consistent with the documentation and the old shell code. Signed-off-by: Sitaram Chamarty Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index a2da314ac6..2f4d6cc87e 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -100,7 +100,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), - OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"), + OPT_BOOLEAN('u', "untracked-files", &untracked_files, "show all untracked files"), OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), -- cgit v1.3 From 960b8ad1b1824b1b82c2b09a000c2119f97633a0 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Mon, 12 May 2008 19:57:45 +0200 Subject: Make the exit code of add_file_to_index actually useful Update the programs which used the function (as add_file_to_cache). Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-add.c | 6 ++++-- builtin-commit.c | 7 ++++--- builtin-mv.c | 3 ++- read-cache.c | 6 +++--- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-add.c b/builtin-add.c index 4a91e3eb11..4d72ab678d 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -94,7 +94,8 @@ static void update_callback(struct diff_queue_struct *q, case DIFF_STATUS_UNMERGED: case DIFF_STATUS_MODIFIED: case DIFF_STATUS_TYPE_CHANGED: - add_file_to_cache(path, verbose); + if (add_file_to_cache(path, verbose)) + die("updating files failed"); break; case DIFF_STATUS_DELETED: remove_file_from_cache(path); @@ -254,7 +255,8 @@ int cmd_add(int argc, const char **argv, const char *prefix) } for (i = 0; i < dir.nr; i++) - add_file_to_cache(dir.entries[i]->name, verbose); + if (add_file_to_cache(dir.entries[i]->name, verbose)) + die("adding files failed"); finish: if (active_cache_changed) { diff --git a/builtin-commit.c b/builtin-commit.c index a65c2b8c37..ae29d35d76 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -178,9 +178,10 @@ static void add_remove_files(struct path_list *list) struct stat st; struct path_list_item *p = &(list->items[i]); - if (!lstat(p->path, &st)) - add_to_cache(p->path, &st, 0); - else + if (!lstat(p->path, &st)) { + if (add_to_cache(p->path, &st, 0)) + die("updating files failed"); + } else remove_file_from_cache(p->path); } } diff --git a/builtin-mv.c b/builtin-mv.c index 94f6dd2aad..fb8ffb41aa 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -256,7 +256,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix) for (i = 0; i < added.nr; i++) { const char *path = added.items[i].path; - add_file_to_cache(path, verbose); + if (add_file_to_cache(path, verbose)) + die("updating index entries failed"); } for (i = 0; i < deleted.nr; i++) diff --git a/read-cache.c b/read-cache.c index 0382804e76..8b467f8f41 100644 --- a/read-cache.c +++ b/read-cache.c @@ -470,7 +470,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY; if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode)) - die("%s: can only add regular files, symbolic links or git-directories", path); + return error("%s: can only add regular files, symbolic links or git-directories", path); namelen = strlen(path); if (S_ISDIR(st_mode)) { @@ -505,12 +505,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, return 0; } if (index_path(ce->sha1, path, st, 1)) - die("unable to index file %s", path); + return error("unable to index file %s", path); if (ignore_case && alias && different_name(ce, alias)) ce = create_alias_ce(ce, alias); ce->ce_flags |= CE_ADDED; if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE)) - die("unable to add %s to index",path); + return error("unable to add %s to index",path); if (verbose) printf("add '%s'\n", path); return 0; -- cgit v1.3 From 7ae02a30e817eda16ea362c6304b6ae28c3a7644 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Mon, 12 May 2008 19:58:10 +0200 Subject: Extend interface of add_files_to_cache to allow ignore indexing errors Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-add.c | 37 ++++++++++++++++++++++++++++--------- builtin-checkout.c | 2 +- builtin-commit.c | 2 +- cache.h | 8 +++++++- 4 files changed, 37 insertions(+), 12 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-add.c b/builtin-add.c index 4d72ab678d..786280818a 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -79,12 +79,18 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec, prune_directory(dir, pathspec, baselen); } +struct update_callback_data +{ + int flags; + int add_errors; +}; + static void update_callback(struct diff_queue_struct *q, struct diff_options *opt, void *cbdata) { - int i, verbose; + int i; + struct update_callback_data *data = cbdata; - verbose = *((int *)cbdata); for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; const char *path = p->one->path; @@ -94,28 +100,35 @@ static void update_callback(struct diff_queue_struct *q, case DIFF_STATUS_UNMERGED: case DIFF_STATUS_MODIFIED: case DIFF_STATUS_TYPE_CHANGED: - if (add_file_to_cache(path, verbose)) - die("updating files failed"); + if (add_file_to_cache(path, data->flags & ADD_FILES_VERBOSE)) { + if (!(data->flags & ADD_FILES_IGNORE_ERRORS)) + die("updating files failed"); + data->add_errors++; + } break; case DIFF_STATUS_DELETED: remove_file_from_cache(path); - if (verbose) + if (data->flags & ADD_FILES_VERBOSE) printf("remove '%s'\n", path); break; } } } -void add_files_to_cache(int verbose, const char *prefix, const char **pathspec) +int add_files_to_cache(const char *prefix, const char **pathspec, int flags) { + struct update_callback_data data; struct rev_info rev; init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.prune_data = pathspec; rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = update_callback; - rev.diffopt.format_callback_data = &verbose; + data.flags = flags; + data.add_errors = 0; + rev.diffopt.format_callback_data = &data; run_diff_files(&rev, DIFF_RACY_IS_MODIFIED); + return !!data.add_errors; } static void refresh(int verbose, const char **pathspec) @@ -193,6 +206,7 @@ static struct option builtin_add_options[] = { int cmd_add(int argc, const char **argv, const char *prefix) { + int exit_status = 0; int i, newfd; const char **pathspec; struct dir_struct dir; @@ -209,11 +223,16 @@ int cmd_add(int argc, const char **argv, const char *prefix) newfd = hold_locked_index(&lock_file, 1); if (take_worktree_changes) { + int flags = 0; const char **pathspec; if (read_cache() < 0) die("index file corrupt"); pathspec = get_pathspec(prefix, argv); - add_files_to_cache(verbose, prefix, pathspec); + + if (verbose) + flags |= ADD_FILES_VERBOSE; + + exit_status = add_files_to_cache(prefix, pathspec, flags); goto finish; } @@ -265,5 +284,5 @@ int cmd_add(int argc, const char **argv, const char *prefix) die("Unable to write new index file"); } - return 0; + return exit_status; } diff --git a/builtin-checkout.c b/builtin-checkout.c index 10ec137cce..05c06421b6 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -282,7 +282,7 @@ static int merge_working_tree(struct checkout_opts *opts, * entries in the index. */ - add_files_to_cache(0, NULL, NULL); + add_files_to_cache(NULL, NULL, 0); work = write_tree_from_memory(); ret = reset_to_new(new->commit->tree, opts->quiet); diff --git a/builtin-commit.c b/builtin-commit.c index ae29d35d76..6a2f5c3d96 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -246,7 +246,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) */ if (all || (also && pathspec && *pathspec)) { int fd = hold_locked_index(&index_lock, 1); - add_files_to_cache(0, also ? prefix : NULL, pathspec); + add_files_to_cache(also ? prefix : NULL, pathspec, 0); refresh_cache(REFRESH_QUIET); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) diff --git a/cache.h b/cache.h index 9cee9a5f3f..4fb629000e 100644 --- a/cache.h +++ b/cache.h @@ -781,7 +781,13 @@ extern int convert_to_git(const char *path, const char *src, size_t len, extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst); /* add */ -void add_files_to_cache(int verbose, const char *prefix, const char **pathspec); +#define ADD_FILES_VERBOSE 01 +#define ADD_FILES_IGNORE_ERRORS 02 +/* + * return 0 if success, 1 - if addition of a file failed and + * ADD_FILES_IGNORE_ERRORS was specified in flags + */ +int add_files_to_cache(const char *prefix, const char **pathspec, int flags); /* diff.c */ extern int diff_auto_refresh_index; -- cgit v1.3 From ef90d6d4208a5130185b04f06e5f90a5f9959fe3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 14 May 2008 18:46:53 +0100 Subject: Provide git_config with a callback-data parameter git_config() only had a function parameter, but no callback data parameter. This assumes that all callback functions only modify global variables. With this patch, every callback gets a void * parameter, and it is hoped that this will help the libification effort. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- alias.c | 5 +++-- archive-tar.c | 6 +++--- builtin-add.c | 2 +- builtin-apply.c | 6 +++--- builtin-blame.c | 6 +++--- builtin-branch.c | 6 +++--- builtin-cat-file.c | 2 +- builtin-checkout-index.c | 2 +- builtin-checkout.c | 2 +- builtin-clean.c | 6 +++--- builtin-commit-tree.c | 2 +- builtin-commit.c | 8 ++++---- builtin-config.c | 26 ++++++++++++++------------ builtin-diff-files.c | 2 +- builtin-diff-index.c | 2 +- builtin-diff-tree.c | 2 +- builtin-diff.c | 2 +- builtin-fast-export.c | 2 +- builtin-fetch-pack.c | 6 +++--- builtin-fmt-merge-msg.c | 4 ++-- builtin-gc.c | 6 +++--- builtin-http-fetch.c | 2 +- builtin-init-db.c | 4 ++-- builtin-log.c | 18 +++++++++--------- builtin-ls-files.c | 2 +- builtin-ls-tree.c | 2 +- builtin-mailinfo.c | 2 +- builtin-merge-base.c | 2 +- builtin-merge-recursive.c | 6 +++--- builtin-mv.c | 2 +- builtin-name-rev.c | 2 +- builtin-pack-objects.c | 6 +++--- builtin-read-tree.c | 4 +--- builtin-reflog.c | 6 +++--- builtin-remote.c | 8 ++++---- builtin-rerere.c | 6 +++--- builtin-reset.c | 2 +- builtin-rev-list.c | 2 +- builtin-rev-parse.c | 2 +- builtin-revert.c | 2 +- builtin-rm.c | 2 +- builtin-show-branch.c | 6 +++--- builtin-symbolic-ref.c | 2 +- builtin-tag.c | 6 +++--- builtin-unpack-objects.c | 2 +- builtin-update-index.c | 2 +- builtin-update-ref.c | 2 +- builtin-verify-pack.c | 2 +- builtin-verify-tag.c | 2 +- builtin-write-tree.c | 2 +- cache.h | 10 +++++----- color.c | 4 ++-- color.h | 2 +- config.c | 27 ++++++++++++++------------- connect.c | 7 ++++--- convert.c | 4 ++-- daemon.c | 4 ++-- diff.c | 8 ++++---- diff.h | 4 ++-- fast-import.c | 6 +++--- hash-object.c | 2 +- help.c | 6 +++--- http.c | 6 +++--- imap-send.c | 4 ++-- index-pack.c | 6 +++--- ll-merge.c | 4 ++-- pager.c | 2 +- receive-pack.c | 6 +++--- remote.c | 4 ++-- setup.c | 4 ++-- unpack-file.c | 2 +- var.c | 8 ++++---- wt-status.c | 4 ++-- wt-status.h | 2 +- 74 files changed, 176 insertions(+), 173 deletions(-) (limited to 'builtin-commit.c') diff --git a/alias.c b/alias.c index 116cac87c3..995f3e6a0a 100644 --- a/alias.c +++ b/alias.c @@ -2,7 +2,8 @@ static const char *alias_key; static char *alias_val; -static int alias_lookup_cb(const char *k, const char *v) + +static int alias_lookup_cb(const char *k, const char *v, void *cb) { if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { if (!v) @@ -17,6 +18,6 @@ char *alias_lookup(const char *alias) { alias_key = alias; alias_val = NULL; - git_config(alias_lookup_cb); + git_config(alias_lookup_cb, NULL); return alias_val; } diff --git a/archive-tar.c b/archive-tar.c index 4add80284e..d7598f907d 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -220,7 +220,7 @@ static void write_global_extended_header(const unsigned char *sha1) strbuf_release(&ext_header); } -static int git_tar_config(const char *var, const char *value) +static int git_tar_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "tar.umask")) { if (value && !strcmp(value, "user")) { @@ -231,7 +231,7 @@ static int git_tar_config(const char *var, const char *value) } return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static int write_tar_entry(const unsigned char *sha1, @@ -268,7 +268,7 @@ int write_tar_archive(struct archiver_args *args) { int plen = args->base ? strlen(args->base) : 0; - git_config(git_tar_config); + git_config(git_tar_config, NULL); archive_time = args->time; verbose = args->verbose; diff --git a/builtin-add.c b/builtin-add.c index 4a91e3eb11..15def7dada 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -203,7 +203,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (add_interactive) exit(interactive_add(argc, argv, prefix)); - git_config(git_default_config); + git_config(git_default_config, NULL); newfd = hold_locked_index(&lock_file, 1); diff --git a/builtin-apply.c b/builtin-apply.c index 1103625a4a..bbdf08a10a 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2979,11 +2979,11 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) return 0; } -static int git_apply_config(const char *var, const char *value) +static int git_apply_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "apply.whitespace")) return git_config_string(&apply_default_whitespace, var, value); - return git_default_config(var, value); + return git_default_config(var, value, cb); } @@ -2999,7 +2999,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) prefix = setup_git_directory_gently(&is_not_gitdir); prefix_length = prefix ? strlen(prefix) : 0; - git_config(git_apply_config); + git_config(git_apply_config, NULL); if (apply_default_whitespace) parse_whitespace_option(apply_default_whitespace); diff --git a/builtin-blame.c b/builtin-blame.c index bfd562d7d2..b451f6c64d 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1993,7 +1993,7 @@ static void prepare_blame_range(struct scoreboard *sb, usage(blame_usage); } -static int git_blame_config(const char *var, const char *value) +static int git_blame_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "blame.showroot")) { show_root = git_config_bool(var, value); @@ -2003,7 +2003,7 @@ static int git_blame_config(const char *var, const char *value) blank_boundary = git_config_bool(var, value); return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static struct commit *fake_working_tree_commit(const char *path, const char *contents_from) @@ -2141,7 +2141,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) cmd_is_annotate = !strcmp(argv[0], "annotate"); - git_config(git_blame_config); + git_config(git_blame_config, NULL); save_commit_buffer = 0; opt = 0; diff --git a/builtin-branch.c b/builtin-branch.c index 19c508a608..d279702ba9 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -63,7 +63,7 @@ static int parse_branch_color_slot(const char *var, int ofs) die("bad config variable '%s'", var); } -static int git_branch_config(const char *var, const char *value) +static int git_branch_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "color.branch")) { branch_use_color = git_config_colorbool(var, value, -1); @@ -76,7 +76,7 @@ static int git_branch_config(const char *var, const char *value) color_parse(value, var, branch_colors[slot]); return 0; } - return git_color_default_config(var, value); + return git_color_default_config(var, value, cb); } static const char *branch_get_color(enum color_branch ix) @@ -461,7 +461,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_END(), }; - git_config(git_branch_config); + git_config(git_branch_config, NULL); if (branch_use_color == -1) branch_use_color = git_use_color_default; diff --git a/builtin-cat-file.c b/builtin-cat-file.c index f132d583d3..b488fad431 100644 --- a/builtin-cat-file.c +++ b/builtin-cat-file.c @@ -85,7 +85,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) int opt; const char *exp_type, *obj_name; - git_config(git_default_config); + git_config(git_default_config, NULL); if (argc != 3) usage("git-cat-file [-t|-s|-e|-p|] "); exp_type = argv[1]; diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 7e42024c67..eb1fc9aa6f 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -166,7 +166,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) int read_from_stdin = 0; int prefix_length; - git_config(git_default_config); + git_config(git_default_config, NULL); state.base_dir = ""; prefix_length = prefix ? strlen(prefix) : 0; diff --git a/builtin-checkout.c b/builtin-checkout.c index 10ec137cce..c077134e62 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -514,7 +514,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) memset(&opts, 0, sizeof(opts)); memset(&new, 0, sizeof(new)); - git_config(git_default_config); + git_config(git_default_config, NULL); opts.track = git_branch_track; diff --git a/builtin-clean.c b/builtin-clean.c index 6778a03ae4..80a7ff9ae4 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -19,11 +19,11 @@ static const char *const builtin_clean_usage[] = { NULL }; -static int git_clean_config(const char *var, const char *value) +static int git_clean_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "clean.requireforce")) force = !git_config_bool(var, value); - return git_default_config(var, value); + return git_default_config(var, value, cb); } int cmd_clean(int argc, const char **argv, const char *prefix) @@ -50,7 +50,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix) OPT_END() }; - git_config(git_clean_config); + git_config(git_clean_config, NULL); if (force < 0) force = 0; else diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 6610d18358..e5e4bdbe86 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -60,7 +60,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) struct strbuf buffer; int encoding_is_utf8; - git_config(git_default_config); + git_config(git_default_config, NULL); if (argc < 2) usage(commit_tree_usage); diff --git a/builtin-commit.c b/builtin-commit.c index a65c2b8c37..9f0026ed00 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -773,7 +773,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) const char *index_file; int commitable; - git_config(git_status_config); + git_config(git_status_config, NULL); if (wt_status_use_color == -1) wt_status_use_color = git_use_color_default; @@ -827,7 +827,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) } } -int git_commit_config(const char *k, const char *v) +int git_commit_config(const char *k, const char *v, void *cb) { if (!strcmp(k, "commit.template")) { if (!v) @@ -836,7 +836,7 @@ int git_commit_config(const char *k, const char *v) return 0; } - return git_status_config(k, v); + return git_status_config(k, v, cb); } static const char commit_utf8_warn[] = @@ -864,7 +864,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) unsigned char commit_sha1[20]; struct ref_lock *ref_lock; - git_config(git_commit_config); + git_config(git_commit_config, NULL); argc = parse_and_validate_options(argc, argv, builtin_commit_usage); diff --git a/builtin-config.c b/builtin-config.c index 8ee01bdecd..3a441ef648 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -18,7 +18,7 @@ static char key_delim = ' '; static char term = '\n'; static enum { T_RAW, T_INT, T_BOOL, T_BOOL_OR_INT } type = T_RAW; -static int show_all_config(const char *key_, const char *value_) +static int show_all_config(const char *key_, const char *value_, void *cb) { if (value_) printf("%s%c%s%c", key_, delim, value_, term); @@ -27,7 +27,7 @@ static int show_all_config(const char *key_, const char *value_) return 0; } -static int show_config(const char* key_, const char* value_) +static int show_config(const char* key_, const char* value_, void *cb) { char value[256]; const char *vptr = value; @@ -121,14 +121,14 @@ static int get_value(const char* key_, const char* regex_) } if (do_all && system_wide) - git_config_from_file(show_config, system_wide); + git_config_from_file(show_config, system_wide, NULL); if (do_all && global) - git_config_from_file(show_config, global); - git_config_from_file(show_config, local); + git_config_from_file(show_config, global, NULL); + git_config_from_file(show_config, local, NULL); if (!do_all && !seen && global) - git_config_from_file(show_config, global); + git_config_from_file(show_config, global, NULL); if (!do_all && !seen && system_wide) - git_config_from_file(show_config, system_wide); + git_config_from_file(show_config, system_wide, NULL); free(key); if (regexp) { @@ -182,7 +182,7 @@ static int get_color_found; static const char *get_color_slot; static char parsed_color[COLOR_MAXLEN]; -static int git_get_color_config(const char *var, const char *value) +static int git_get_color_config(const char *var, const char *value, void *cb) { if (!strcmp(var, get_color_slot)) { if (!value) @@ -218,7 +218,7 @@ static int get_color(int argc, const char **argv) get_color_found = 0; parsed_color[0] = '\0'; - git_config(git_get_color_config); + git_config(git_get_color_config, NULL); if (!get_color_found && def_color) color_parse(def_color, "command line", parsed_color); @@ -230,7 +230,8 @@ static int get_color(int argc, const char **argv) static int stdout_is_tty; static int get_colorbool_found; static int get_diff_color_found; -static int git_get_colorbool_config(const char *var, const char *value) +static int git_get_colorbool_config(const char *var, const char *value, + void *cb) { if (!strcmp(var, get_color_slot)) { get_colorbool_found = @@ -265,7 +266,7 @@ static int get_colorbool(int argc, const char **argv) get_colorbool_found = -1; get_diff_color_found = -1; get_color_slot = argv[0]; - git_config(git_get_colorbool_config); + git_config(git_get_colorbool_config, NULL); if (get_colorbool_found < 0) { if (!strcmp(get_color_slot, "color.diff")) @@ -298,7 +299,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) { if (argc != 2) usage(git_config_set_usage); - if (git_config(show_all_config) < 0 && file && errno) + if (git_config(show_all_config, NULL) < 0 && + file && errno) die("unable to read config file %s: %s", file, strerror(errno)); return 0; diff --git a/builtin-diff-files.c b/builtin-diff-files.c index e2306c162a..907392a1f3 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -21,7 +21,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix) prefix = setup_git_directory_gently(&nongit); init_revisions(&rev, prefix); - git_config(git_diff_basic_config); /* no "diff" UI options */ + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; if (!setup_diff_no_index(&rev, argc, argv, nongit, prefix)) diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 2b955deb91..2f44ebfcdd 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -17,7 +17,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) int result; init_revisions(&rev, prefix); - git_config(git_diff_basic_config); /* no "diff" UI options */ + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ rev.abbrev = 0; argc = setup_revisions(argc, argv, &rev, NULL); diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 832797ff3b..9d2a48fd68 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -68,7 +68,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix) int read_stdin = 0; init_revisions(opt, prefix); - git_config(git_diff_basic_config); /* no "diff" UI options */ + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ nr_sha1 = 0; opt->abbrev = 0; opt->diff = 1; diff --git a/builtin-diff.c b/builtin-diff.c index 7c2a8412fa..583291a9c0 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -234,7 +234,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) */ prefix = setup_git_directory_gently(&nongit); - git_config(git_diff_ui_config); + git_config(git_diff_ui_config, NULL); if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; diff --git a/builtin-fast-export.c b/builtin-fast-export.c index e1c56303e5..ff759cc578 100755 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -372,7 +372,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) }; /* we handle encodings */ - git_config(git_default_config); + git_config(git_default_config, NULL); init_revisions(&revs, prefix); argc = setup_revisions(argc, argv, &revs, NULL); diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index c97a42739d..de1e8d1365 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -635,7 +635,7 @@ static int remove_duplicates(int nr_heads, char **heads) return dst; } -static int fetch_pack_config(const char *var, const char *value) +static int fetch_pack_config(const char *var, const char *value, void *cb) { if (strcmp(var, "fetch.unpacklimit") == 0) { fetch_unpack_limit = git_config_int(var, value); @@ -647,7 +647,7 @@ static int fetch_pack_config(const char *var, const char *value) return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static struct lock_file lock; @@ -657,7 +657,7 @@ static void fetch_pack_setup(void) static int did_setup; if (did_setup) return; - git_config(fetch_pack_config); + git_config(fetch_pack_config, NULL); if (0 <= transfer_unpack_limit) unpack_limit = transfer_unpack_limit; else if (0 <= fetch_unpack_limit) diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index b72cb59e6a..b892621ab5 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -10,7 +10,7 @@ static const char *fmt_merge_msg_usage = static int merge_summary; -static int fmt_merge_msg_config(const char *key, const char *value) +static int fmt_merge_msg_config(const char *key, const char *value, void *cb) { static int found_merge_log = 0; if (!strcmp("merge.log", key)) { @@ -260,7 +260,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) unsigned char head_sha1[20]; const char *current_branch; - git_config(fmt_merge_msg_config); + git_config(fmt_merge_msg_config, NULL); while (argc > 1) { if (!strcmp(argv[1], "--log") || !strcmp(argv[1], "--summary")) diff --git a/builtin-gc.c b/builtin-gc.c index f99ebc7926..e1a329917a 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -35,7 +35,7 @@ static const char *argv_repack[MAX_ADD] = {"repack", "-d", "-l", NULL}; static const char *argv_prune[] = {"prune", "--expire", NULL, NULL}; static const char *argv_rerere[] = {"rerere", "gc", NULL}; -static int gc_config(const char *var, const char *value) +static int gc_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "gc.packrefs")) { if (value && !strcmp(value, "notbare")) @@ -67,7 +67,7 @@ static int gc_config(const char *var, const char *value) prune_expire = xstrdup(value); return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static void append_option(const char **cmd, const char *opt, int max_length) @@ -226,7 +226,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) OPT_END() }; - git_config(gc_config); + git_config(gc_config, NULL); if (pack_refs < 0) pack_refs = !is_bare_repository(); diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c index b1f33891c3..3a062487a7 100644 --- a/builtin-http-fetch.c +++ b/builtin-http-fetch.c @@ -18,7 +18,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) int get_verbosely = 0; int get_recover = 0; - git_config(git_default_config); + git_config(git_default_config, NULL); while (arg < argc && argv[arg][0] == '-') { if (argv[arg][1] == 't') { diff --git a/builtin-init-db.c b/builtin-init-db.c index a76f5d3474..f6aa353529 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -142,7 +142,7 @@ static void copy_templates(const char *git_dir, int len, const char *template_di strcpy(template_path + template_len, "config"); repository_format_version = 0; git_config_from_file(check_repository_format_version, - template_path); + template_path, NULL); template_path[template_len] = 0; if (repository_format_version && @@ -197,7 +197,7 @@ static int create_default_files(const char *git_dir, const char *template_path) path[len] = 0; copy_templates(path, len, template_path); - git_config(git_default_config); + git_config(git_default_config, NULL); /* * We would have created the above under user's umask -- under diff --git a/builtin-log.c b/builtin-log.c index 80a01f8d44..addc7098cf 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -222,7 +222,7 @@ static int cmd_log_walk(struct rev_info *rev) return 0; } -static int git_log_config(const char *var, const char *value) +static int git_log_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "format.pretty")) return git_config_string(&fmt_pretty, var, value); @@ -236,14 +236,14 @@ static int git_log_config(const char *var, const char *value) default_show_root = git_config_bool(var, value); return 0; } - return git_diff_ui_config(var, value); + return git_diff_ui_config(var, value, cb); } int cmd_whatchanged(int argc, const char **argv, const char *prefix) { struct rev_info rev; - git_config(git_log_config); + git_config(git_log_config, NULL); if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; @@ -319,7 +319,7 @@ int cmd_show(int argc, const char **argv, const char *prefix) struct object_array_entry *objects; int i, count, ret = 0; - git_config(git_log_config); + git_config(git_log_config, NULL); if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; @@ -383,7 +383,7 @@ int cmd_log_reflog(int argc, const char **argv, const char *prefix) { struct rev_info rev; - git_config(git_log_config); + git_config(git_log_config, NULL); if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; @@ -416,7 +416,7 @@ int cmd_log(int argc, const char **argv, const char *prefix) { struct rev_info rev; - git_config(git_log_config); + git_config(git_log_config, NULL); if (diff_use_color_default == -1) diff_use_color_default = git_use_color_default; @@ -471,7 +471,7 @@ static void add_header(const char *value) extra_hdr[extra_hdr_nr++] = xstrndup(value, len); } -static int git_format_config(const char *var, const char *value) +static int git_format_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "format.headers")) { if (!value) @@ -497,7 +497,7 @@ static int git_format_config(const char *var, const char *value) return 0; } - return git_log_config(var, value); + return git_log_config(var, value, cb); } @@ -764,7 +764,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) char *add_signoff = NULL; struct strbuf buf; - git_config(git_format_config); + git_config(git_format_config, NULL); init_revisions(&rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; rev.verbose_header = 1; diff --git a/builtin-ls-files.c b/builtin-ls-files.c index dc7eab89b3..75ba42246e 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -437,7 +437,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) memset(&dir, 0, sizeof(dir)); if (prefix) prefix_offset = strlen(prefix); - git_config(git_default_config); + git_config(git_default_config, NULL); for (i = 1; i < argc; i++) { const char *arg = argv[i]; diff --git a/builtin-ls-tree.c b/builtin-ls-tree.c index 7abe333ce9..f4a75ddbc3 100644 --- a/builtin-ls-tree.c +++ b/builtin-ls-tree.c @@ -122,7 +122,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix) unsigned char sha1[20]; struct tree *tree; - git_config(git_default_config); + git_config(git_default_config, NULL); ls_tree_prefix = prefix; if (prefix && *prefix) chomp_prefix = strlen(prefix); diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index 11f154b31f..6e23ffd8af 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -962,7 +962,7 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix) /* NEEDSWORK: might want to do the optional .git/ directory * discovery */ - git_config(git_default_config); + git_config(git_default_config, NULL); def_charset = (git_commit_encoding ? git_commit_encoding : "utf-8"); metainfo_charset = def_charset; diff --git a/builtin-merge-base.c b/builtin-merge-base.c index 0108e22ade..bcf9395aaf 100644 --- a/builtin-merge-base.c +++ b/builtin-merge-base.c @@ -28,7 +28,7 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix) unsigned char rev1key[20], rev2key[20]; int show_all = 0; - git_config(git_default_config); + git_config(git_default_config, NULL); while (1 < argc && argv[1][0] == '-') { const char *arg = argv[1]; diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 910c0d20e7..e16f5e2a4e 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -1336,7 +1336,7 @@ static struct commit *get_ref(const char *ref) return (struct commit *)object; } -static int merge_config(const char *var, const char *value) +static int merge_config(const char *var, const char *value, void *cb) { if (!strcasecmp(var, "merge.verbosity")) { verbosity = git_config_int(var, value); @@ -1346,7 +1346,7 @@ static int merge_config(const char *var, const char *value) rename_limit = git_config_int(var, value); return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } int cmd_merge_recursive(int argc, const char **argv, const char *prefix) @@ -1367,7 +1367,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) subtree_merge = 1; } - git_config(merge_config); + git_config(merge_config, NULL); if (getenv("GIT_MERGE_VERBOSITY")) verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); diff --git a/builtin-mv.c b/builtin-mv.c index 94f6dd2aad..3edebef45f 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -81,7 +81,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) struct path_list deleted = {NULL, 0, 0, 0}; struct path_list changed = {NULL, 0, 0, 0}; - git_config(git_default_config); + git_config(git_default_config, NULL); newfd = hold_locked_index(&lock_file, 1); if (read_cache() < 0) diff --git a/builtin-name-rev.c b/builtin-name-rev.c index 384da4db13..cde5de56fa 100644 --- a/builtin-name-rev.c +++ b/builtin-name-rev.c @@ -195,7 +195,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix) OPT_END(), }; - git_config(git_default_config); + git_config(git_default_config, NULL); argc = parse_options(argc, argv, opts, name_rev_usage, 0); if (!!all + !!transform_stdin + !!argc > 1) { error("Specify either a list, or --all, not both!"); diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 777f272668..a8dc225a72 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1718,7 +1718,7 @@ static void prepare_pack(int window, int depth) free(delta_list); } -static int git_pack_config(const char *k, const char *v) +static int git_pack_config(const char *k, const char *v, void *cb) { if(!strcmp(k, "pack.window")) { window = git_config_int(k, v); @@ -1771,7 +1771,7 @@ static int git_pack_config(const char *k, const char *v) pack_size_limit_cfg = git_config_ulong(k, v); return 0; } - return git_default_config(k, v); + return git_default_config(k, v, cb); } static void read_object_list_from_stdin(void) @@ -1963,7 +1963,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) rp_av[1] = "--objects"; /* --thin will make it --objects-edge */ rp_ac = 2; - git_config(git_pack_config); + git_config(git_pack_config, NULL); if (!pack_compression_seen && core_compression_seen) pack_compression_level = core_compression_level; diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 7ac30883bc..5a09e17f1a 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -104,12 +104,10 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) opts.src_index = &the_index; opts.dst_index = &the_index; - git_config(git_default_config); + git_config(git_default_config, NULL); newfd = hold_locked_index(&lock_file, 1); - git_config(git_default_config); - for (i = 1; i < argc; i++) { const char *arg = argv[i]; diff --git a/builtin-reflog.c b/builtin-reflog.c index 280e24e151..897d1dcac6 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -329,7 +329,7 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused return 0; } -static int reflog_expire_config(const char *var, const char *value) +static int reflog_expire_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "gc.reflogexpire")) { if (!value) @@ -343,7 +343,7 @@ static int reflog_expire_config(const char *var, const char *value) default_reflog_expire_unreachable = approxidate(value); return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) @@ -352,7 +352,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) unsigned long now = time(NULL); int i, status, do_all; - git_config(reflog_expire_config); + git_config(reflog_expire_config, NULL); save_commit_buffer = 0; do_all = status = 0; diff --git a/builtin-remote.c b/builtin-remote.c index 8b63619ef0..99a34dfe86 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -153,7 +153,7 @@ struct branch_info { static struct path_list branch_list; -static int config_read_branches(const char *key, const char *value) +static int config_read_branches(const char *key, const char *value, void *cb) { if (!prefixcmp(key, "branch.")) { char *name; @@ -200,7 +200,7 @@ static void read_branches(void) { if (branch_list.nr) return; - git_config(config_read_branches); + git_config(config_read_branches, NULL); sort_path_list(&branch_list); } @@ -514,7 +514,7 @@ struct remote_group { struct path_list *list; } remote_group; -static int get_remote_group(const char *key, const char *value) +static int get_remote_group(const char *key, const char *value, void *cb) { if (!prefixcmp(key, "remotes.") && !strcmp(key + 8, remote_group.name)) { @@ -546,7 +546,7 @@ static int update(int argc, const char **argv) remote_group.list = &list; for (i = 1; i < argc; i++) { remote_group.name = argv[i]; - result = git_config(get_remote_group); + result = git_config(get_remote_group, NULL); } if (!result && !list.nr && argc == 2 && !strcmp(argv[1], "default")) diff --git a/builtin-rerere.c b/builtin-rerere.c index c607aade63..5c811423cc 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -339,7 +339,7 @@ tail_optimization: return write_rr(rr, fd); } -static int git_rerere_config(const char *var, const char *value) +static int git_rerere_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "gc.rerereresolved")) cutoff_resolve = git_config_int(var, value); @@ -348,7 +348,7 @@ static int git_rerere_config(const char *var, const char *value) else if (!strcmp(var, "rerere.enabled")) rerere_enabled = git_config_bool(var, value); else - return git_default_config(var, value); + return git_default_config(var, value, cb); return 0; } @@ -376,7 +376,7 @@ static int setup_rerere(struct path_list *merge_rr) { int fd; - git_config(git_rerere_config); + git_config(git_rerere_config, NULL); if (!is_rerere_enabled()) return -1; diff --git a/builtin-reset.c b/builtin-reset.c index 79424bb26e..e32ddd90ac 100644 --- a/builtin-reset.c +++ b/builtin-reset.c @@ -186,7 +186,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) OPT_END() }; - git_config(git_default_config); + git_config(git_default_config, NULL); argc = parse_options(argc, argv, options, git_reset_usage, PARSE_OPT_KEEP_DASHDASH); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index edc0bd35bb..274299044e 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -546,7 +546,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) int bisect_find_all = 0; int quiet = 0; - git_config(git_default_config); + git_config(git_default_config, NULL); init_revisions(&revs, prefix); revs.abbrev = 0; revs.commit_format = CMIT_FMT_UNSPECIFIED; diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index f8d8548e9c..1d019b3c16 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -381,7 +381,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) return cmd_parseopt(argc - 1, argv + 1, prefix); prefix = setup_git_directory(); - git_config(git_default_config); + git_config(git_default_config, NULL); for (i = 1; i < argc; i++) { const char *arg = argv[i]; diff --git a/builtin-revert.c b/builtin-revert.c index 2b57525d72..0270f9b85a 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -269,7 +269,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) const char *message, *encoding; const char *defmsg = xstrdup(git_path("MERGE_MSG")); - git_config(git_default_config); + git_config(git_default_config, NULL); me = action == REVERT ? "revert" : "cherry-pick"; setenv(GIT_REFLOG_ACTION, me, 0); parse_args(argc, argv); diff --git a/builtin-rm.c b/builtin-rm.c index c0a8bb6cf5..22c9bd1c6c 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -144,7 +144,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) const char **pathspec; char *seen; - git_config(git_default_config); + git_config(git_default_config, NULL); newfd = hold_locked_index(&lock_file, 1); diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 019abd3527..ee4269dd33 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -533,7 +533,7 @@ static void append_one_rev(const char *av) die("bad sha1 reference %s", av); } -static int git_show_branch_config(const char *var, const char *value) +static int git_show_branch_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "showbranch.default")) { if (!value) @@ -547,7 +547,7 @@ static int git_show_branch_config(const char *var, const char *value) return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static int omit_in_dense(struct commit *commit, struct commit **rev, int n) @@ -611,7 +611,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) int reflog = 0; const char *reflog_base = NULL; - git_config(git_show_branch_config); + git_config(git_show_branch_config, NULL); /* If nothing is specified, try the default first */ if (ac == 1 && default_num) { diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c index d33982b967..b49bdb6900 100644 --- a/builtin-symbolic-ref.c +++ b/builtin-symbolic-ref.c @@ -35,7 +35,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) OPT_END(), }; - git_config(git_default_config); + git_config(git_default_config, NULL); argc = parse_options(argc, argv, options, git_symbolic_ref_usage, 0); if (msg &&!*msg) die("Refusing to perform update with empty message"); diff --git a/builtin-tag.c b/builtin-tag.c index 129ff57f11..e675206de3 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -256,7 +256,7 @@ static void set_signingkey(const char *value) die("signing key value too long (%.10s...)", value); } -static int git_tag_config(const char *var, const char *value) +static int git_tag_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "user.signingkey")) { if (!value) @@ -265,7 +265,7 @@ static int git_tag_config(const char *var, const char *value) return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static void write_tag_body(int fd, const unsigned char *sha1) @@ -408,7 +408,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) OPT_END() }; - git_config(git_tag_config); + git_config(git_tag_config, NULL); argc = parse_options(argc, argv, options, git_tag_usage, 0); diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index fecf0be779..85043d1fde 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -493,7 +493,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) int i; unsigned char sha1[20]; - git_config(git_default_config); + git_config(git_default_config, NULL); quiet = !isatty(2); diff --git a/builtin-update-index.c b/builtin-update-index.c index a8795d3d5f..e1ca8deac2 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -567,7 +567,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) int lock_error = 0; struct lock_file *lock_file; - git_config(git_default_config); + git_config(git_default_config, NULL); /* We can't free this memory, it becomes part of a linked list parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); diff --git a/builtin-update-ref.c b/builtin-update-ref.c index e90737c350..93c127196d 100644 --- a/builtin-update-ref.c +++ b/builtin-update-ref.c @@ -22,7 +22,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix) OPT_END(), }; - git_config(git_default_config); + git_config(git_default_config, NULL); argc = parse_options(argc, argv, options, git_update_ref_usage, 0); if (msg && !*msg) die("Refusing to perform update with empty message."); diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c index 4958bbbf11..4c515a0570 100644 --- a/builtin-verify-pack.c +++ b/builtin-verify-pack.c @@ -55,7 +55,7 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix) int no_more_options = 0; int nothing_done = 1; - git_config(git_default_config); + git_config(git_default_config, NULL); while (1 < argc) { if (!no_more_options && argv[1][0] == '-') { if (!strcmp("-v", argv[1])) diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index db81496b46..92eaa89a45 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -90,7 +90,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; - git_config(git_default_config); + git_config(git_default_config, NULL); if (argc == 1) usage(builtin_verify_tag_usage); diff --git a/builtin-write-tree.c b/builtin-write-tree.c index e838d01233..c218799744 100644 --- a/builtin-write-tree.c +++ b/builtin-write-tree.c @@ -18,7 +18,7 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix) unsigned char sha1[20]; const char *me = "git-write-tree"; - git_config(git_default_config); + git_config(git_default_config, NULL); while (1 < argc) { const char *arg = argv[1]; if (!strcmp(arg, "--missing-ok")) diff --git a/cache.h b/cache.h index 9cee9a5f3f..ebe4031b65 100644 --- a/cache.h +++ b/cache.h @@ -711,10 +711,10 @@ extern int matches_pack_name(struct packed_git *p, const char *name); /* Dumb servers support */ extern int update_server_info(int); -typedef int (*config_fn_t)(const char *, const char *); -extern int git_default_config(const char *, const char *); -extern int git_config_from_file(config_fn_t fn, const char *); -extern int git_config(config_fn_t fn); +typedef int (*config_fn_t)(const char *, const char *, void *); +extern int git_default_config(const char *, const char *, void *); +extern int git_config_from_file(config_fn_t fn, const char *, void *); +extern int git_config(config_fn_t fn, void *); extern int git_parse_long(const char *, long *); extern int git_parse_ulong(const char *, unsigned long *); extern int git_config_int(const char *, const char *); @@ -726,7 +726,7 @@ extern int git_config_set(const char *, const char *); extern int git_config_set_multivar(const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); extern const char *git_etc_gitconfig(void); -extern int check_repository_format_version(const char *var, const char *value); +extern int check_repository_format_version(const char *var, const char *value, void *cb); extern int git_env_bool(const char *, int); extern int git_config_system(void); extern int git_config_global(void); diff --git a/color.c b/color.c index 12a6453f90..fc0b72ad59 100644 --- a/color.c +++ b/color.c @@ -145,14 +145,14 @@ int git_config_colorbool(const char *var, const char *value, int stdout_is_tty) return 0; } -int git_color_default_config(const char *var, const char *value) +int git_color_default_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "color.ui")) { git_use_color_default = git_config_colorbool(var, value, -1); return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static int color_vfprintf(FILE *fp, const char *color, const char *fmt, diff --git a/color.h b/color.h index ecda5569a2..6cf5c88aaf 100644 --- a/color.h +++ b/color.h @@ -13,7 +13,7 @@ extern int git_use_color_default; /* * Use this instead of git_default_config if you need the value of color.ui. */ -int git_color_default_config(const char *var, const char *value); +int git_color_default_config(const char *var, const char *value, void *cb); int git_config_colorbool(const char *var, const char *value, int stdout_is_tty); void color_parse(const char *var, const char *value, char *dst); diff --git a/config.c b/config.c index 0e22c7a642..5431e2dc01 100644 --- a/config.c +++ b/config.c @@ -111,7 +111,7 @@ static inline int iskeychar(int c) return isalnum(c) || c == '-'; } -static int get_value(config_fn_t fn, char *name, unsigned int len) +static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) { int c; char *value; @@ -139,7 +139,7 @@ static int get_value(config_fn_t fn, char *name, unsigned int len) if (!value) return -1; } - return fn(name, value); + return fn(name, value, data); } static int get_extended_base_var(char *name, int baselen, int c) @@ -197,7 +197,7 @@ static int get_base_var(char *name) } } -static int git_parse_file(config_fn_t fn) +static int git_parse_file(config_fn_t fn, void *data) { int comment = 0; int baselen = 0; @@ -228,7 +228,7 @@ static int git_parse_file(config_fn_t fn) if (!isalpha(c)) break; var[baselen] = tolower(c); - if (get_value(fn, var, baselen+1) < 0) + if (get_value(fn, data, var, baselen+1) < 0) break; } die("bad config file line %d in %s", config_linenr, config_file_name); @@ -332,7 +332,7 @@ int git_config_string(const char **dest, const char *var, const char *value) return 0; } -int git_default_config(const char *var, const char *value) +int git_default_config(const char *var, const char *value, void *dummy) { /* This needs a better name */ if (!strcmp(var, "core.filemode")) { @@ -512,7 +512,7 @@ int git_default_config(const char *var, const char *value) return 0; } -int git_config_from_file(config_fn_t fn, const char *filename) +int git_config_from_file(config_fn_t fn, const char *filename, void *data) { int ret; FILE *f = fopen(filename, "r"); @@ -523,7 +523,7 @@ int git_config_from_file(config_fn_t fn, const char *filename) config_file_name = filename; config_linenr = 1; config_file_eof = 0; - ret = git_parse_file(fn); + ret = git_parse_file(fn, data); fclose(f); config_file_name = NULL; } @@ -561,7 +561,7 @@ int git_config_global(void) return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0); } -int git_config(config_fn_t fn) +int git_config(config_fn_t fn, void *data) { int ret = 0; char *repo_config = NULL; @@ -574,7 +574,8 @@ int git_config(config_fn_t fn) filename = getenv(CONFIG_ENVIRONMENT); if (!filename) { if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) - ret += git_config_from_file(fn, git_etc_gitconfig()); + ret += git_config_from_file(fn, git_etc_gitconfig(), + data); home = getenv("HOME"); filename = getenv(CONFIG_LOCAL_ENVIRONMENT); if (!filename) @@ -584,11 +585,11 @@ int git_config(config_fn_t fn) if (git_config_global() && home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); if (!access(user_config, R_OK)) - ret = git_config_from_file(fn, user_config); + ret = git_config_from_file(fn, user_config, data); free(user_config); } - ret += git_config_from_file(fn, filename); + ret += git_config_from_file(fn, filename, data); free(repo_config); return ret; } @@ -618,7 +619,7 @@ static int matches(const char* key, const char* value) !regexec(store.value_regex, value, 0, NULL, 0))); } -static int store_aux(const char* key, const char* value) +static int store_aux(const char* key, const char* value, void *cb) { const char *ep; size_t section_len; @@ -947,7 +948,7 @@ int git_config_set_multivar(const char* key, const char* value, * As a side effect, we make sure to transform only a valid * existing config file. */ - if (git_config_from_file(store_aux, config_filename)) { + if (git_config_from_file(store_aux, config_filename, NULL)) { error("invalid config file %s", config_filename); free(store.key); if (store.value_regex != NULL) { diff --git a/connect.c b/connect.c index d12b105970..e92af29735 100644 --- a/connect.c +++ b/connect.c @@ -360,7 +360,8 @@ static char *git_proxy_command; static const char *rhost_name; static int rhost_len; -static int git_proxy_command_options(const char *var, const char *value) +static int git_proxy_command_options(const char *var, const char *value, + void *cb) { if (!strcmp(var, "core.gitproxy")) { const char *for_pos; @@ -404,7 +405,7 @@ static int git_proxy_command_options(const char *var, const char *value) return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static int git_use_proxy(const char *host) @@ -412,7 +413,7 @@ static int git_use_proxy(const char *host) rhost_name = host; rhost_len = strlen(host); git_proxy_command = getenv("GIT_PROXY_COMMAND"); - git_config(git_proxy_command_options); + git_config(git_proxy_command_options, NULL); rhost_name = NULL; return (git_proxy_command && *git_proxy_command); } diff --git a/convert.c b/convert.c index d8c94cb3ed..1c66844783 100644 --- a/convert.c +++ b/convert.c @@ -323,7 +323,7 @@ static struct convert_driver { char *clean; } *user_convert, **user_convert_tail; -static int read_convert_config(const char *var, const char *value) +static int read_convert_config(const char *var, const char *value, void *cb) { const char *ep, *name; int namelen; @@ -385,7 +385,7 @@ static void setup_convert_check(struct git_attr_check *check) attr_ident = git_attr("ident", 5); attr_filter = git_attr("filter", 6); user_convert_tail = &user_convert; - git_config(read_convert_config); + git_config(read_convert_config, NULL); } check[0].attr = attr_crlf; check[1].attr = attr_ident; diff --git a/daemon.c b/daemon.c index 2b4a6f145c..63cd12cd9c 100644 --- a/daemon.c +++ b/daemon.c @@ -306,7 +306,7 @@ struct daemon_service { static struct daemon_service *service_looking_at; static int service_enabled; -static int git_daemon_config(const char *var, const char *value) +static int git_daemon_config(const char *var, const char *value, void *cb) { if (!prefixcmp(var, "daemon.") && !strcmp(var + 7, service_looking_at->config_name)) { @@ -356,7 +356,7 @@ static int run_service(struct interp *itable, struct daemon_service *service) if (service->overridable) { service_looking_at = service; service_enabled = -1; - git_config(git_daemon_config); + git_config(git_daemon_config, NULL); if (0 <= service_enabled) enabled = service_enabled; } diff --git a/diff.c b/diff.c index e35384b444..1f46ff0f08 100644 --- a/diff.c +++ b/diff.c @@ -129,7 +129,7 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v * never be affected by the setting of diff.renames * the user happens to have in the configuration file. */ -int git_diff_ui_config(const char *var, const char *value) +int git_diff_ui_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.renamelimit")) { diff_rename_limit_default = git_config_int(var, value); @@ -166,10 +166,10 @@ int git_diff_ui_config(const char *var, const char *value) return parse_lldiff_command(var, ep, value); } - return git_diff_basic_config(var, value); + return git_diff_basic_config(var, value, cb); } -int git_diff_basic_config(const char *var, const char *value) +int git_diff_basic_config(const char *var, const char *value, void *cb) { if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); @@ -190,7 +190,7 @@ int git_diff_basic_config(const char *var, const char *value) } } - return git_color_default_config(var, value); + return git_color_default_config(var, value, cb); } static char *quote_two(const char *one, const char *two) diff --git a/diff.h b/diff.h index 1bd94a4807..1cf1eff485 100644 --- a/diff.h +++ b/diff.h @@ -180,8 +180,8 @@ extern void diff_unmerge(struct diff_options *, #define DIFF_SETUP_USE_CACHE 2 #define DIFF_SETUP_USE_SIZE_CACHE 4 -extern int git_diff_basic_config(const char *var, const char *value); -extern int git_diff_ui_config(const char *var, const char *value); +extern int git_diff_basic_config(const char *var, const char *value, void *cb); +extern int git_diff_ui_config(const char *var, const char *value, void *cb); extern int diff_use_color_default; extern void diff_setup(struct diff_options *); extern int diff_opt_parse(struct diff_options *, const char **, int); diff --git a/fast-import.c b/fast-import.c index 73e5439d97..36ec5b87f8 100644 --- a/fast-import.c +++ b/fast-import.c @@ -2352,7 +2352,7 @@ static void import_marks(const char *input_file) fclose(f); } -static int git_pack_config(const char *k, const char *v) +static int git_pack_config(const char *k, const char *v, void *cb) { if (!strcmp(k, "pack.depth")) { max_depth = git_config_int(k, v); @@ -2370,7 +2370,7 @@ static int git_pack_config(const char *k, const char *v) pack_compression_seen = 1; return 0; } - return git_default_config(k, v); + return git_default_config(k, v, cb); } static const char fast_import_usage[] = @@ -2381,7 +2381,7 @@ int main(int argc, const char **argv) unsigned int i, show_stats = 1; setup_git_directory(); - git_config(git_pack_config); + git_config(git_pack_config, NULL); if (!pack_compression_seen && core_compression_seen) pack_compression_level = core_compression_level; diff --git a/hash-object.c b/hash-object.c index 61e7160b36..3d773900ff 100644 --- a/hash-object.c +++ b/hash-object.c @@ -43,7 +43,7 @@ int main(int argc, char **argv) int no_more_flags = 0; int hashstdin = 0; - git_config(git_default_config); + git_config(git_default_config, NULL); for (i = 1 ; i < argc; i++) { if (!no_more_flags && argv[i][0] == '-') { diff --git a/help.c b/help.c index af80979fcb..d89d43796f 100644 --- a/help.c +++ b/help.c @@ -252,7 +252,7 @@ static int add_man_viewer_info(const char *var, const char *value) return 0; } -static int git_help_config(const char *var, const char *value) +static int git_help_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "help.format")) { if (!value) @@ -269,7 +269,7 @@ static int git_help_config(const char *var, const char *value) if (!prefixcmp(var, "man.")) return add_man_viewer_info(var, value); - return git_default_config(var, value); + return git_default_config(var, value, cb); } /* most GUI terminals set COLUMNS (although some don't export it) */ @@ -641,7 +641,7 @@ int cmd_help(int argc, const char **argv, const char *prefix) const char *alias; setup_git_directory_gently(&nongit); - git_config(git_help_config); + git_config(git_help_config, NULL); argc = parse_options(argc, argv, builtin_help_options, builtin_help_usage, 0); diff --git a/http.c b/http.c index acf746a12d..2a21ccbb76 100644 --- a/http.c +++ b/http.c @@ -90,7 +90,7 @@ static void process_curl_messages(void) } #endif -static int http_options(const char *var, const char *value) +static int http_options(const char *var, const char *value, void *cb) { if (!strcmp("http.sslverify", var)) { if (curl_ssl_verify == -1) { @@ -169,7 +169,7 @@ static int http_options(const char *var, const char *value) } /* Fall back on the default ones */ - return git_default_config(var, value); + return git_default_config(var, value, cb); } static CURL* get_curl_handle(void) @@ -263,7 +263,7 @@ void http_init(struct remote *remote) if (low_speed_time != NULL) curl_low_speed_time = strtol(low_speed_time, NULL, 10); - git_config(http_options); + git_config(http_options, NULL); if (curl_ssl_verify == -1) curl_ssl_verify = 1; diff --git a/imap-send.c b/imap-send.c index db6559725e..1ec1310921 100644 --- a/imap-send.c +++ b/imap-send.c @@ -1247,7 +1247,7 @@ static imap_server_conf_t server = static char *imap_folder; static int -git_imap_config(const char *key, const char *val) +git_imap_config(const char *key, const char *val, void *cb) { char imap_key[] = "imap."; @@ -1296,7 +1296,7 @@ main(int argc, char **argv) /* init the random number generator */ arc4_init(); - git_config( git_imap_config ); + git_config(git_imap_config, NULL); if (!imap_folder) { fprintf( stderr, "no imap store specified\n" ); diff --git a/index-pack.c b/index-pack.c index 9c0c27813f..aaba9443cc 100644 --- a/index-pack.c +++ b/index-pack.c @@ -765,7 +765,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name, } } -static int git_index_pack_config(const char *k, const char *v) +static int git_index_pack_config(const char *k, const char *v, void *cb) { if (!strcmp(k, "pack.indexversion")) { pack_idx_default_version = git_config_int(k, v); @@ -773,7 +773,7 @@ static int git_index_pack_config(const char *k, const char *v) die("bad pack.indexversion=%d", pack_idx_default_version); return 0; } - return git_default_config(k, v); + return git_default_config(k, v, cb); } int main(int argc, char **argv) @@ -786,7 +786,7 @@ int main(int argc, char **argv) struct pack_idx_entry **idx_objects; unsigned char sha1[20]; - git_config(git_index_pack_config); + git_config(git_index_pack_config, NULL); for (i = 1; i < argc; i++) { char *arg = argv[i]; diff --git a/ll-merge.c b/ll-merge.c index 5ae74331bc..9837c842a3 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -225,7 +225,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, static struct ll_merge_driver *ll_user_merge, **ll_user_merge_tail; static const char *default_ll_merge; -static int read_merge_config(const char *var, const char *value) +static int read_merge_config(const char *var, const char *value, void *cb) { struct ll_merge_driver *fn; const char *ep, *name; @@ -309,7 +309,7 @@ static void initialize_ll_merge(void) if (ll_user_merge_tail) return; ll_user_merge_tail = &ll_user_merge; - git_config(read_merge_config); + git_config(read_merge_config, NULL); } static const struct ll_merge_driver *find_ll_merge_driver(const char *merge_attr) diff --git a/pager.c b/pager.c index ca002f9f79..dbd941421b 100644 --- a/pager.c +++ b/pager.c @@ -33,7 +33,7 @@ void setup_pager(void) return; if (!pager) { if (!pager_program) - git_config(git_default_config); + git_config(git_default_config, NULL); pager = pager_program; } if (!pager) diff --git a/receive-pack.c b/receive-pack.c index 828d49001d..b26f2e3a41 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -19,7 +19,7 @@ static int report_status; static char capabilities[] = " report-status delete-refs "; static int capabilities_sent; -static int receive_pack_config(const char *var, const char *value) +static int receive_pack_config(const char *var, const char *value, void *cb) { if (strcmp(var, "receive.denynonfastforwards") == 0) { deny_non_fast_forwards = git_config_bool(var, value); @@ -41,7 +41,7 @@ static int receive_pack_config(const char *var, const char *value) return 0; } - return git_default_config(var, value); + return git_default_config(var, value, cb); } static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data) @@ -489,7 +489,7 @@ int main(int argc, char **argv) if (is_repository_shallow()) die("attempt to push into a shallow repository"); - git_config(receive_pack_config); + git_config(receive_pack_config, NULL); if (0 <= transfer_unpack_limit) unpack_limit = transfer_unpack_limit; diff --git a/remote.c b/remote.c index 91cbb72dde..dff6c5f686 100644 --- a/remote.c +++ b/remote.c @@ -288,7 +288,7 @@ static void read_branches_file(struct remote *remote) remote->fetch_tags = 1; /* always auto-follow */ } -static int handle_config(const char *key, const char *value) +static int handle_config(const char *key, const char *value, void *cb) { const char *name; const char *subkey; @@ -410,7 +410,7 @@ static void read_config(void) current_branch = make_branch(head_ref + strlen("refs/heads/"), 0); } - git_config(handle_config); + git_config(handle_config, NULL); alias_all_urls(); } diff --git a/setup.c b/setup.c index b8fd476395..d630e374e7 100644 --- a/setup.c +++ b/setup.c @@ -300,7 +300,7 @@ void setup_work_tree(void) static int check_repository_format_gently(int *nongit_ok) { - git_config(check_repository_format_version); + git_config(check_repository_format_version, NULL); if (GIT_REPO_VERSION < repository_format_version) { if (!nongit_ok) die ("Expected git repo version <= %d, found %d", @@ -524,7 +524,7 @@ int git_config_perm(const char *var, const char *value) return i & 0666; } -int check_repository_format_version(const char *var, const char *value) +int check_repository_format_version(const char *var, const char *value, void *cb) { if (strcmp(var, "core.repositoryformatversion") == 0) repository_format_version = git_config_int(var, value); diff --git a/unpack-file.c b/unpack-file.c index 65c66eb0bf..bcdc8bbb3b 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -31,7 +31,7 @@ int main(int argc, char **argv) die("Not a valid object name %s", argv[1]); setup_git_directory(); - git_config(git_default_config); + git_config(git_default_config, NULL); puts(create_temp_file(sha1)); return 0; diff --git a/var.c b/var.c index c20ac919bd..724ba87a7c 100644 --- a/var.c +++ b/var.c @@ -39,13 +39,13 @@ static const char *read_var(const char *var) return val; } -static int show_config(const char *var, const char *value) +static int show_config(const char *var, const char *value, void *cb) { if (value) printf("%s=%s\n", var, value); else printf("%s\n", var); - return git_default_config(var, value); + return git_default_config(var, value, cb); } int main(int argc, char **argv) @@ -60,11 +60,11 @@ int main(int argc, char **argv) val = NULL; if (strcmp(argv[1], "-l") == 0) { - git_config(show_config); + git_config(show_config, NULL); list_vars(); return 0; } - git_config(git_default_config); + git_config(git_default_config, NULL); val = read_var(argv[1]); if (!val) usage(var_usage); diff --git a/wt-status.c b/wt-status.c index 532b4ea2c1..c932b39d20 100644 --- a/wt-status.c +++ b/wt-status.c @@ -362,7 +362,7 @@ void wt_status_print(struct wt_status *s) } } -int git_status_config(const char *k, const char *v) +int git_status_config(const char *k, const char *v, void *cb) { if (!strcmp(k, "status.submodulesummary")) { int is_bool; @@ -386,5 +386,5 @@ int git_status_config(const char *k, const char *v) wt_status_relative_paths = git_config_bool(k, v); return 0; } - return git_color_default_config(k, v); + return git_color_default_config(k, v, cb); } diff --git a/wt-status.h b/wt-status.h index 7d61410b17..f2c71302cb 100644 --- a/wt-status.h +++ b/wt-status.h @@ -27,7 +27,7 @@ struct wt_status { const char *prefix; }; -int git_status_config(const char *var, const char *value); +int git_status_config(const char *var, const char *value, void *cb); extern int wt_status_use_color; extern int wt_status_relative_paths; void wt_status_prepare(struct wt_status *s); -- cgit v1.3 From d5350fd2b3a4721885bf1b3353478970caef268c Mon Sep 17 00:00:00 2001 From: Gerrit Pape Date: Tue, 27 May 2008 08:59:16 +0000 Subject: commit --interactive: properly update the index before commiting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When adding files through git commit --interactive, and 'quit' afterwards, the message in the editor of the commit message indicates that many (maybe all) files are deleted from the tree. Dismissing that and running git commit afterwards does the right thing. This commit fixes git commit --interactive to properly update the index before commiting. Reported by Jiří Paleček through http://bugs.debian.org/480429 Signed-off-by: Gerrit Pape Signed-off-by: Junio C Hamano --- builtin-commit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index e3564a526a..b0fe69ecad 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -219,6 +219,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) if (interactive) { interactive_add(argc, argv, prefix); + if (read_cache() < 0) + die("index file corrupt"); commit_style = COMMIT_AS_IS; return get_index_file(); } -- cgit v1.3 From 67bfc030d7b27c007853776e8028598bdfa2cae0 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 2 Jun 2008 22:17:42 -0700 Subject: commit: drop duplicated parents The scripted version of git-commit internally used git-commit-tree which omitted duplicated parents given from the command line. This prevented a nonsensical octopus merge from getting created even when you said "git merge A B" while you are already on branch A. However, when git-commit was rewritten in C, this sanity check was lost. This resurrects it. Signed-off-by: Junio C Hamano --- builtin-commit.c | 9 +++++++++ t/t7502-commit.sh | 14 ++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index b294c1f88c..90200ed643 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -883,10 +883,19 @@ static void add_parent(struct strbuf *sb, const unsigned char *sha1) { struct object *obj = parse_object(sha1); const char *parent = sha1_to_hex(sha1); + const char *cp; + if (!obj) die("Unable to find commit parent %s", parent); if (obj->type != OBJ_COMMIT) die("Parent %s isn't a proper commit", parent); + + for (cp = sb->buf; cp && (cp = strstr(cp, "\nparent ")); cp += 8) { + if (!memcmp(cp + 8, parent, 40) && cp[48] == '\n') { + error("duplicate parent %s ignored", parent); + return; + } + } strbuf_addf(sb, "parent %s\n", parent); } diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 46ec1ce8aa..22a13f7aab 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -226,4 +226,18 @@ test_expect_success 'a SIGTERM should break locks' ' ! test -f .git/index.lock ' +rm -f .git/MERGE_MSG .git/COMMIT_EDITMSG +git reset -q --hard + +test_expect_success 'Hand committing of a redundant merge removes dups' ' + + git rev-parse second master >expect && + test_must_fail git merge second master && + git checkout master g && + EDITOR=: git commit -a && + git cat-file commit HEAD | sed -n -e "s/^parent //p" -e "/^$/q" >actual && + test_cmp expect actual + +' + test_done -- cgit v1.3 From 4bfee30a98783f7987c395e6006a2a6717344c04 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 5 Jun 2008 10:31:19 +0200 Subject: Add an optional argument to commit/status -u|--untracked-files option This lets you specify how you want untracked files to be listed. The possible options are: normal - Show untracked files and directories all - Show all untracked files The 'all' mode is used, if the mode is not specified. Signed-off-by: Marius Storm-Olsen --- Documentation/git-commit.txt | 18 ++++++++----- builtin-commit.c | 16 +++++++++--- t/t7502-status.sh | 61 ++++++++++++++++++++++++++++++++++++++++++++ wt-status.c | 1 + wt-status.h | 6 +++++ 5 files changed, 92 insertions(+), 10 deletions(-) (limited to 'builtin-commit.c') diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 02d4baab6d..e600e14be5 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -8,7 +8,7 @@ git-commit - Record changes to the repository SYNOPSIS -------- [verse] -'git-commit' [-a | --interactive] [-s] [-v] [-u] +'git-commit' [-a | --interactive] [-s] [-v] [-u[]] [(-c | -C) | -F | -m | --amend] [--allow-empty] [--no-verify] [-e] [--author ] [--cleanup=] [--] [[-i | -o ]...] @@ -150,12 +150,16 @@ but can be used to amend a merge commit. the last commit without committing changes that have already been staged. --u|--untracked-files:: - Show all untracked files, also those in uninteresting - directories, in the "Untracked files:" section of commit - message template. Without this option only its name and - a trailing slash are displayed for each untracked - directory. +-u[]|--untracked-files[=]:: + Show untracked files (Default: 'all'). ++ +The mode parameter is optional, and is used to specify +the handling of untracked files. The possible options are: ++ +-- + - 'normal' - Shows untracked files and directories + - 'all' - Also shows individual files in untracked directories. +-- -v|--verbose:: Show unified diff between the HEAD commit and what diff --git a/builtin-commit.c b/builtin-commit.c index 90200ed643..446a1086fd 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -49,7 +49,8 @@ static char *logfile, *force_author, *template_file; static char *edit_message, *use_message; static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; -static int quiet, verbose, untracked_files, no_verify, allow_empty; +static int quiet, verbose, no_verify, allow_empty; +static char *untracked_files_arg; /* * The default commit message cleanup mode will remove the lines * beginning with # (shell comments) and leading and trailing @@ -102,7 +103,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), - OPT_BOOLEAN('u', "untracked-files", &untracked_files, "show all untracked files"), + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), @@ -347,7 +348,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int s.reference = "HEAD^1"; } s.verbose = verbose; - s.untracked = untracked_files; + s.untracked = (show_untracked_files == SHOW_ALL_UNTRACKED_FILES); s.index_file = index_file; s.fp = fp; s.nowarn = nowarn; @@ -795,6 +796,15 @@ static int parse_and_validate_options(int argc, const char *argv[], else die("Invalid cleanup mode %s", cleanup_arg); + if (!untracked_files_arg) + ; /* default already initialized */ + else if (!strcmp(untracked_files_arg, "normal")) + show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; + else if (!strcmp(untracked_files_arg, "all")) + show_untracked_files = SHOW_ALL_UNTRACKED_FILES; + else + die("Invalid untracked files mode '%s'", untracked_files_arg); + if (all && argc > 0) die("Paths with -a does not make sense."); else if (interactive && argc > 0) diff --git a/t/t7502-status.sh b/t/t7502-status.sh index 80a438d4d9..0d24e259fb 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -67,6 +67,67 @@ test_expect_success 'status (2)' ' ' +cat >expect <..." to unstage) +# +# new file: dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# dir1/untracked +# dir2/modified +# dir2/untracked +# dir3/ +# expect +# output +# untracked +EOF +test_expect_success 'status -unormal' ' + mkdir dir3 && + : > dir3/untracked1 && + : > dir3/untracked2 && + git status -unormal >output && + test_cmp expect output +' + +cat >expect <..." to unstage) +# +# new file: dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# +# modified: dir1/modified +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# dir1/untracked +# dir2/modified +# dir2/untracked +# dir3/untracked1 +# dir3/untracked2 +# expect +# output +# untracked +EOF +test_expect_success 'status -uall' ' + git status -uall >output && + rm -rf dir3 && + test_cmp expect output +' + cat > expect << \EOF # On branch master # Changes to be committed: diff --git a/wt-status.c b/wt-status.c index 5b4d74c1f3..25d998513e 100644 --- a/wt-status.c +++ b/wt-status.c @@ -27,6 +27,7 @@ static const char use_add_rm_msg[] = "use \"git add/rm ...\" to update what will be committed"; static const char use_add_to_include_msg[] = "use \"git add ...\" to include in what will be committed"; +enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; static int parse_status_slot(const char *var, int offset) { diff --git a/wt-status.h b/wt-status.h index 597c7ea988..54f756de2b 100644 --- a/wt-status.h +++ b/wt-status.h @@ -11,6 +11,12 @@ enum color_wt_status { WT_STATUS_NOBRANCH, }; +enum untracked_status_type { + SHOW_NORMAL_UNTRACKED_FILES = 1, + SHOW_ALL_UNTRACKED_FILES +}; +extern enum untracked_status_type show_untracked_files; + struct wt_status { int is_initial; char *branch; -- cgit v1.3 From 6c2ce048bbfc6fbc2bdd86a3e586cb8881eb2dc2 Mon Sep 17 00:00:00 2001 From: Marius Storm-Olsen Date: Thu, 5 Jun 2008 14:22:56 +0200 Subject: Add argument 'no' commit/status option -u|--untracked-files This new argument teaches Git to not look for any untracked files, saving cycles on slow file systems, or large repos. Signed-off-by: Marius Storm-Olsen --- Documentation/git-commit.txt | 1 + builtin-commit.c | 4 +++- t/t7502-status.sh | 25 ++++++++++++++++++++++--- wt-status.c | 7 ++++++- wt-status.h | 3 ++- 5 files changed, 34 insertions(+), 6 deletions(-) (limited to 'builtin-commit.c') diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index e600e14be5..a6f41f3663 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -157,6 +157,7 @@ The mode parameter is optional, and is used to specify the handling of untracked files. The possible options are: + -- + - 'no' - Show no untracked files - 'normal' - Shows untracked files and directories - 'all' - Also shows individual files in untracked directories. -- diff --git a/builtin-commit.c b/builtin-commit.c index 446a1086fd..0a70808280 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -103,7 +103,7 @@ static struct option builtin_commit_options[] = { OPT_BOOLEAN('o', "only", &only, "commit only specified files"), OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"), OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"), - { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, + { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, OPT_BOOLEAN(0, "allow-empty", &allow_empty, "ok to record an empty change"), OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"), @@ -798,6 +798,8 @@ static int parse_and_validate_options(int argc, const char *argv[], if (!untracked_files_arg) ; /* default already initialized */ + else if (!strcmp(untracked_files_arg, "no")) + show_untracked_files = SHOW_NO_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "normal")) show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; else if (!strcmp(untracked_files_arg, "all")) diff --git a/t/t7502-status.sh b/t/t7502-status.sh index 0d24e259fb..d84bda1dda 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -67,6 +67,28 @@ test_expect_success 'status (2)' ' ' +cat >expect <..." to unstage) +# +# new file: dir2/added +# +# Changed but not updated: +# (use "git add ..." to update what will be committed) +# +# modified: dir1/modified +# +# Untracked files not listed (use -u option to show untracked files) +EOF +test_expect_success 'status -uno' ' + mkdir dir3 && + : > dir3/untracked1 && + : > dir3/untracked2 && + git status -uno >output && + test_cmp expect output +' + cat >expect <expect < dir3/untracked1 && - : > dir3/untracked2 && git status -unormal >output && test_cmp expect output ' diff --git a/wt-status.c b/wt-status.c index 25d998513e..23017e4d46 100644 --- a/wt-status.c +++ b/wt-status.c @@ -348,7 +348,10 @@ void wt_status_print(struct wt_status *s) wt_status_print_changed(s); if (wt_status_submodule_summary) wt_status_print_submodule_summary(s); - wt_status_print_untracked(s); + if (show_untracked_files) + wt_status_print_untracked(s); + else if (s->commitable) + fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n"); if (s->verbose && !s->is_initial) wt_status_print_verbose(s); @@ -363,6 +366,8 @@ void wt_status_print(struct wt_status *s) printf("nothing added to commit but untracked files present (use \"git add\" to track)\n"); else if (s->is_initial) printf("nothing to commit (create/copy files and use \"git add\" to track)\n"); + else if (!show_untracked_files) + printf("nothing to commit (use -u to show untracked files)\n"); else printf("nothing to commit (working directory clean)\n"); } diff --git a/wt-status.h b/wt-status.h index 54f756de2b..78add09bd6 100644 --- a/wt-status.h +++ b/wt-status.h @@ -12,7 +12,8 @@ enum color_wt_status { }; enum untracked_status_type { - SHOW_NORMAL_UNTRACKED_FILES = 1, + SHOW_NO_UNTRACKED_FILES, + SHOW_NORMAL_UNTRACKED_FILES, SHOW_ALL_UNTRACKED_FILES }; extern enum untracked_status_type show_untracked_files; -- cgit v1.3 From cdeaf10f7e2754054c7be5d74227c698d2a71890 Mon Sep 17 00:00:00 2001 From: Cristian Peraferrer Date: Fri, 20 Jun 2008 17:24:20 +0200 Subject: Print errno upon failure to open the COMMIT_EDITMSG file When the COMMIT_EDITMSG cannot be opened, give more information to the user by giving the 'errno' information. Signed-off-by: Cristian Peraferrer Signed-off-by: Junio C Hamano --- builtin-commit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 90200ed643..a33f43a209 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -502,7 +502,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix) fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) - die("could not open %s", git_path(commit_editmsg)); + die("could not open %s: %s", + git_path(commit_editmsg), strerror(errno)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); -- cgit v1.3 From 984c6e7ec1f7f6278a207b7d6178962f85130d10 Mon Sep 17 00:00:00 2001 From: Brian Hetro Date: Sat, 5 Jul 2008 01:24:40 -0400 Subject: builtin-commit.c: Use 'git_config_string' to get 'commit.template' Signed-off-by: Brian Hetro Signed-off-by: Junio C Hamano --- builtin-commit.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-commit.c b/builtin-commit.c index 90200ed643..bcbea3893b 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -45,7 +45,8 @@ static enum { COMMIT_PARTIAL, } commit_style; -static char *logfile, *force_author, *template_file; +static char *logfile, *force_author; +static const char *template_file; static char *edit_message, *use_message; static char *author_name, *author_email, *author_date; static int all, edit_flag, also, interactive, only, amend, signoff; @@ -864,12 +865,8 @@ static void print_summary(const char *prefix, const unsigned char *sha1) int git_commit_config(const char *k, const char *v, void *cb) { - if (!strcmp(k, "commit.template")) { - if (!v) - return config_error_nonbool(v); - template_file = xstrdup(v); - return 0; - } + if (!strcmp(k, "commit.template")) + return git_config_string(&template_file, k, v); return git_status_config(k, v, cb); } -- cgit v1.3 From 5b2fd95606cd6d564f96d9d253e7cd19263bc352 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Wed, 9 Jul 2008 14:58:57 +0200 Subject: rerere: Separate libgit and builtin functions This patch moves rerere()-related functions into a newly created rerere.c file. The setup_rerere() function is needed by both rerere() and cmd_rerere(), so this function is moved to rerere.c and declared non-static (and "extern") in newly created rerere.h file. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- Makefile | 2 + builtin-commit.c | 1 + builtin-rerere.c | 372 +++---------------------------------------------------- commit.h | 1 - rerere.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rerere.h | 9 ++ 6 files changed, 390 insertions(+), 355 deletions(-) create mode 100644 rerere.c create mode 100644 rerere.h (limited to 'builtin-commit.c') diff --git a/Makefile b/Makefile index 4796565ab3..de151638bb 100644 --- a/Makefile +++ b/Makefile @@ -363,6 +363,7 @@ LIB_H += quote.h LIB_H += reflog-walk.h LIB_H += refs.h LIB_H += remote.h +LIB_H += rerere.h LIB_H += revision.h LIB_H += run-command.h LIB_H += sha1-lookup.h @@ -447,6 +448,7 @@ LIB_OBJS += read-cache.o LIB_OBJS += reflog-walk.o LIB_OBJS += refs.o LIB_OBJS += remote.o +LIB_OBJS += rerere.o LIB_OBJS += revision.o LIB_OBJS += run-command.o LIB_OBJS += server-info.o diff --git a/builtin-commit.c b/builtin-commit.c index 745c11e773..bdc83df55b 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -22,6 +22,7 @@ #include "utf8.h" #include "parse-options.h" #include "path-list.h" +#include "rerere.h" #include "unpack-trees.h" static const char * const builtin_commit_usage[] = { diff --git a/builtin-rerere.c b/builtin-rerere.c index 69c3a52d5e..5d40e16932 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -1,11 +1,10 @@ #include "builtin.h" #include "cache.h" #include "path-list.h" +#include "rerere.h" #include "xdiff/xdiff.h" #include "xdiff-interface.h" -#include - static const char git_rerere_usage[] = "git-rerere [clear | status | diff | gc]"; @@ -13,14 +12,6 @@ static const char git_rerere_usage[] = static int cutoff_noresolve = 15; static int cutoff_resolve = 60; -/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */ -static int rerere_enabled = -1; - -/* automatically update cleanly resolved paths to the index */ -static int rerere_autoupdate; - -static char *merge_rr_path; - static const char *rr_path(const char *name, const char *file) { return git_path("rr-cache/%s/%s", name, file); @@ -38,189 +29,6 @@ static int has_resolution(const char *name) return !stat(rr_path(name, "postimage"), &st); } -static void read_rr(struct path_list *rr) -{ - unsigned char sha1[20]; - char buf[PATH_MAX]; - FILE *in = fopen(merge_rr_path, "r"); - if (!in) - return; - while (fread(buf, 40, 1, in) == 1) { - int i; - char *name; - if (get_sha1_hex(buf, sha1)) - die("corrupt MERGE_RR"); - buf[40] = '\0'; - name = xstrdup(buf); - if (fgetc(in) != '\t') - die("corrupt MERGE_RR"); - for (i = 0; i < sizeof(buf) && (buf[i] = fgetc(in)); i++) - ; /* do nothing */ - if (i == sizeof(buf)) - die("filename too long"); - path_list_insert(buf, rr)->util = name; - } - fclose(in); -} - -static struct lock_file write_lock; - -static int write_rr(struct path_list *rr, int out_fd) -{ - int i; - for (i = 0; i < rr->nr; i++) { - const char *path; - int length; - if (!rr->items[i].util) - continue; - path = rr->items[i].path; - length = strlen(path) + 1; - if (write_in_full(out_fd, rr->items[i].util, 40) != 40 || - write_in_full(out_fd, "\t", 1) != 1 || - write_in_full(out_fd, path, length) != length) - die("unable to write rerere record"); - } - if (commit_lock_file(&write_lock) != 0) - die("unable to write rerere record"); - return 0; -} - -static int handle_file(const char *path, - unsigned char *sha1, const char *output) -{ - SHA_CTX ctx; - char buf[1024]; - int hunk = 0, hunk_no = 0; - struct strbuf one, two; - FILE *f = fopen(path, "r"); - FILE *out = NULL; - - if (!f) - return error("Could not open %s", path); - - if (output) { - out = fopen(output, "w"); - if (!out) { - fclose(f); - return error("Could not write %s", output); - } - } - - if (sha1) - SHA1_Init(&ctx); - - strbuf_init(&one, 0); - strbuf_init(&two, 0); - while (fgets(buf, sizeof(buf), f)) { - if (!prefixcmp(buf, "<<<<<<< ")) { - if (hunk) - goto bad; - hunk = 1; - } else if (!prefixcmp(buf, "=======") && isspace(buf[7])) { - if (hunk != 1) - goto bad; - hunk = 2; - } else if (!prefixcmp(buf, ">>>>>>> ")) { - if (hunk != 2) - goto bad; - if (strbuf_cmp(&one, &two) > 0) - strbuf_swap(&one, &two); - hunk_no++; - hunk = 0; - if (out) { - fputs("<<<<<<<\n", out); - fwrite(one.buf, one.len, 1, out); - fputs("=======\n", out); - fwrite(two.buf, two.len, 1, out); - fputs(">>>>>>>\n", out); - } - if (sha1) { - SHA1_Update(&ctx, one.buf ? one.buf : "", - one.len + 1); - SHA1_Update(&ctx, two.buf ? two.buf : "", - two.len + 1); - } - strbuf_reset(&one); - strbuf_reset(&two); - } else if (hunk == 1) - strbuf_addstr(&one, buf); - else if (hunk == 2) - strbuf_addstr(&two, buf); - else if (out) - fputs(buf, out); - continue; - bad: - hunk = 99; /* force error exit */ - break; - } - strbuf_release(&one); - strbuf_release(&two); - - fclose(f); - if (out) - fclose(out); - if (sha1) - SHA1_Final(sha1, &ctx); - if (hunk) { - if (output) - unlink(output); - return error("Could not parse conflict hunks in %s", path); - } - return hunk_no; -} - -static int find_conflict(struct path_list *conflict) -{ - int i; - if (read_cache() < 0) - return error("Could not read index"); - for (i = 0; i+1 < active_nr; i++) { - struct cache_entry *e2 = active_cache[i]; - struct cache_entry *e3 = active_cache[i+1]; - if (ce_stage(e2) == 2 && - ce_stage(e3) == 3 && - ce_same_name(e2, e3) && - S_ISREG(e2->ce_mode) && - S_ISREG(e3->ce_mode)) { - path_list_insert((const char *)e2->name, conflict); - i++; /* skip over both #2 and #3 */ - } - } - return 0; -} - -static int merge(const char *name, const char *path) -{ - int ret; - mmfile_t cur, base, other; - mmbuffer_t result = {NULL, 0}; - xpparam_t xpp = {XDF_NEED_MINIMAL}; - - if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0) - return 1; - - if (read_mmfile(&cur, rr_path(name, "thisimage")) || - read_mmfile(&base, rr_path(name, "preimage")) || - read_mmfile(&other, rr_path(name, "postimage"))) - return 1; - ret = xdl_merge(&base, &cur, "", &other, "", - &xpp, XDL_MERGE_ZEALOUS, &result); - if (!ret) { - FILE *f = fopen(path, "w"); - if (!f) - return error("Could not write to %s", path); - fwrite(result.ptr, result.size, 1, f); - fclose(f); - } - - free(cur.ptr); - free(base.ptr); - free(other.ptr); - free(result.ptr); - - return ret; -} - static void unlink_rr_item(const char *name) { unlink(rr_path(name, "thisimage")); @@ -229,6 +37,17 @@ static void unlink_rr_item(const char *name) rmdir(git_path("rr-cache/%s", name)); } +static int git_rerere_gc_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "gc.rerereresolved")) + cutoff_resolve = git_config_int(var, value); + else if (!strcmp(var, "gc.rerereunresolved")) + cutoff_noresolve = git_config_int(var, value); + else + return git_default_config(var, value, cb); + return 0; +} + static void garbage_collect(struct path_list *rr) { struct path_list to_remove = { NULL, 0, 0, 1 }; @@ -237,6 +56,7 @@ static void garbage_collect(struct path_list *rr) int i, cutoff; time_t now = time(NULL), then; + git_config(git_rerere_gc_config, NULL); dir = opendir(git_path("rr-cache")); while ((e = readdir(dir))) { const char *name = e->d_name; @@ -289,181 +109,25 @@ static int diff_two(const char *file1, const char *label1, return 0; } -static struct lock_file index_lock; - -static int update_paths(struct path_list *update) -{ - int i; - int fd = hold_locked_index(&index_lock, 0); - int status = 0; - - if (fd < 0) - return -1; - - for (i = 0; i < update->nr; i++) { - struct path_list_item *item = &update->items[i]; - if (add_file_to_cache(item->path, ADD_CACHE_IGNORE_ERRORS)) - status = -1; - } - - if (!status && active_cache_changed) { - if (write_cache(fd, active_cache, active_nr) || - commit_locked_index(&index_lock)) - die("Unable to write new index file"); - } else if (fd >= 0) - rollback_lock_file(&index_lock); - return status; -} - -static int do_plain_rerere(struct path_list *rr, int fd) -{ - struct path_list conflict = { NULL, 0, 0, 1 }; - struct path_list update = { NULL, 0, 0, 1 }; - int i; - - find_conflict(&conflict); - - /* - * MERGE_RR records paths with conflicts immediately after merge - * failed. Some of the conflicted paths might have been hand resolved - * in the working tree since then, but the initial run would catch all - * and register their preimages. - */ - - for (i = 0; i < conflict.nr; i++) { - const char *path = conflict.items[i].path; - if (!path_list_has_path(rr, path)) { - unsigned char sha1[20]; - char *hex; - int ret; - ret = handle_file(path, sha1, NULL); - if (ret < 1) - continue; - hex = xstrdup(sha1_to_hex(sha1)); - path_list_insert(path, rr)->util = hex; - if (mkdir(git_path("rr-cache/%s", hex), 0755)) - continue;; - handle_file(path, NULL, rr_path(hex, "preimage")); - fprintf(stderr, "Recorded preimage for '%s'\n", path); - } - } - - /* - * Now some of the paths that had conflicts earlier might have been - * hand resolved. Others may be similar to a conflict already that - * was resolved before. - */ - - for (i = 0; i < rr->nr; i++) { - int ret; - const char *path = rr->items[i].path; - const char *name = (const char *)rr->items[i].util; - - if (has_resolution(name)) { - if (!merge(name, path)) { - fprintf(stderr, "Resolved '%s' using " - "previous resolution.\n", path); - if (rerere_autoupdate) - path_list_insert(path, &update); - goto mark_resolved; - } - } - - /* Let's see if we have resolved it. */ - ret = handle_file(path, NULL, NULL); - if (ret) - continue; - - fprintf(stderr, "Recorded resolution for '%s'.\n", path); - copy_file(rr_path(name, "postimage"), path, 0666); - mark_resolved: - rr->items[i].util = NULL; - } - - if (update.nr) - update_paths(&update); - - return write_rr(rr, fd); -} - -static int git_rerere_config(const char *var, const char *value, void *cb) -{ - if (!strcmp(var, "gc.rerereresolved")) - cutoff_resolve = git_config_int(var, value); - else if (!strcmp(var, "gc.rerereunresolved")) - cutoff_noresolve = git_config_int(var, value); - else if (!strcmp(var, "rerere.enabled")) - rerere_enabled = git_config_bool(var, value); - else if (!strcmp(var, "rerere.autoupdate")) - rerere_autoupdate = git_config_bool(var, value); - else - return git_default_config(var, value, cb); - return 0; -} - -static int is_rerere_enabled(void) -{ - struct stat st; - const char *rr_cache; - int rr_cache_exists; - - if (!rerere_enabled) - return 0; - - rr_cache = git_path("rr-cache"); - rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode); - if (rerere_enabled < 0) - return rr_cache_exists; - - if (!rr_cache_exists && - (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache))) - die("Could not create directory %s", rr_cache); - return 1; -} - -static int setup_rerere(struct path_list *merge_rr) -{ - int fd; - - git_config(git_rerere_config, NULL); - if (!is_rerere_enabled()) - return -1; - - merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR")); - fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1); - read_rr(merge_rr); - return fd; -} - -int rerere(void) -{ - struct path_list merge_rr = { NULL, 0, 0, 1 }; - int fd; - - fd = setup_rerere(&merge_rr); - if (fd < 0) - return 0; - return do_plain_rerere(&merge_rr, fd); -} - int cmd_rerere(int argc, const char **argv, const char *prefix) { struct path_list merge_rr = { NULL, 0, 0, 1 }; int i, fd; + if (argc < 2) + return rerere(); + fd = setup_rerere(&merge_rr); if (fd < 0) return 0; - if (argc < 2) - return do_plain_rerere(&merge_rr, fd); - else if (!strcmp(argv[1], "clear")) { + if (!strcmp(argv[1], "clear")) { for (i = 0; i < merge_rr.nr; i++) { const char *name = (const char *)merge_rr.items[i].util; if (!has_resolution(name)) unlink_rr_item(name); } - unlink(merge_rr_path); + unlink(git_path("rr-cache/MERGE_RR")); } else if (!strcmp(argv[1], "gc")) garbage_collect(&merge_rr); else if (!strcmp(argv[1], "status")) diff --git a/commit.h b/commit.h index 2d94d4148e..fda7ad03c0 100644 --- a/commit.h +++ b/commit.h @@ -131,7 +131,6 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads, int in_merge_bases(struct commit *, struct commit **, int); extern int interactive_add(int argc, const char **argv, const char *prefix); -extern int rerere(void); static inline int single_parent(struct commit *commit) { diff --git a/rerere.c b/rerere.c new file mode 100644 index 0000000000..eec2b50107 --- /dev/null +++ b/rerere.c @@ -0,0 +1,360 @@ +#include "cache.h" +#include "path-list.h" +#include "rerere.h" +#include "xdiff/xdiff.h" +#include "xdiff-interface.h" + +/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */ +static int rerere_enabled = -1; + +/* automatically update cleanly resolved paths to the index */ +static int rerere_autoupdate; + +static char *merge_rr_path; + +static const char *rr_path(const char *name, const char *file) +{ + return git_path("rr-cache/%s/%s", name, file); +} + +static int has_resolution(const char *name) +{ + struct stat st; + return !stat(rr_path(name, "postimage"), &st); +} + +static void read_rr(struct path_list *rr) +{ + unsigned char sha1[20]; + char buf[PATH_MAX]; + FILE *in = fopen(merge_rr_path, "r"); + if (!in) + return; + while (fread(buf, 40, 1, in) == 1) { + int i; + char *name; + if (get_sha1_hex(buf, sha1)) + die("corrupt MERGE_RR"); + buf[40] = '\0'; + name = xstrdup(buf); + if (fgetc(in) != '\t') + die("corrupt MERGE_RR"); + for (i = 0; i < sizeof(buf) && (buf[i] = fgetc(in)); i++) + ; /* do nothing */ + if (i == sizeof(buf)) + die("filename too long"); + path_list_insert(buf, rr)->util = name; + } + fclose(in); +} + +static struct lock_file write_lock; + +static int write_rr(struct path_list *rr, int out_fd) +{ + int i; + for (i = 0; i < rr->nr; i++) { + const char *path; + int length; + if (!rr->items[i].util) + continue; + path = rr->items[i].path; + length = strlen(path) + 1; + if (write_in_full(out_fd, rr->items[i].util, 40) != 40 || + write_in_full(out_fd, "\t", 1) != 1 || + write_in_full(out_fd, path, length) != length) + die("unable to write rerere record"); + } + if (commit_lock_file(&write_lock) != 0) + die("unable to write rerere record"); + return 0; +} + +static int handle_file(const char *path, + unsigned char *sha1, const char *output) +{ + SHA_CTX ctx; + char buf[1024]; + int hunk = 0, hunk_no = 0; + struct strbuf one, two; + FILE *f = fopen(path, "r"); + FILE *out = NULL; + + if (!f) + return error("Could not open %s", path); + + if (output) { + out = fopen(output, "w"); + if (!out) { + fclose(f); + return error("Could not write %s", output); + } + } + + if (sha1) + SHA1_Init(&ctx); + + strbuf_init(&one, 0); + strbuf_init(&two, 0); + while (fgets(buf, sizeof(buf), f)) { + if (!prefixcmp(buf, "<<<<<<< ")) { + if (hunk) + goto bad; + hunk = 1; + } else if (!prefixcmp(buf, "=======") && isspace(buf[7])) { + if (hunk != 1) + goto bad; + hunk = 2; + } else if (!prefixcmp(buf, ">>>>>>> ")) { + if (hunk != 2) + goto bad; + if (strbuf_cmp(&one, &two) > 0) + strbuf_swap(&one, &two); + hunk_no++; + hunk = 0; + if (out) { + fputs("<<<<<<<\n", out); + fwrite(one.buf, one.len, 1, out); + fputs("=======\n", out); + fwrite(two.buf, two.len, 1, out); + fputs(">>>>>>>\n", out); + } + if (sha1) { + SHA1_Update(&ctx, one.buf ? one.buf : "", + one.len + 1); + SHA1_Update(&ctx, two.buf ? two.buf : "", + two.len + 1); + } + strbuf_reset(&one); + strbuf_reset(&two); + } else if (hunk == 1) + strbuf_addstr(&one, buf); + else if (hunk == 2) + strbuf_addstr(&two, buf); + else if (out) + fputs(buf, out); + continue; + bad: + hunk = 99; /* force error exit */ + break; + } + strbuf_release(&one); + strbuf_release(&two); + + fclose(f); + if (out) + fclose(out); + if (sha1) + SHA1_Final(sha1, &ctx); + if (hunk) { + if (output) + unlink(output); + return error("Could not parse conflict hunks in %s", path); + } + return hunk_no; +} + +static int find_conflict(struct path_list *conflict) +{ + int i; + if (read_cache() < 0) + return error("Could not read index"); + for (i = 0; i+1 < active_nr; i++) { + struct cache_entry *e2 = active_cache[i]; + struct cache_entry *e3 = active_cache[i+1]; + if (ce_stage(e2) == 2 && + ce_stage(e3) == 3 && + ce_same_name(e2, e3) && + S_ISREG(e2->ce_mode) && + S_ISREG(e3->ce_mode)) { + path_list_insert((const char *)e2->name, conflict); + i++; /* skip over both #2 and #3 */ + } + } + return 0; +} + +static int merge(const char *name, const char *path) +{ + int ret; + mmfile_t cur, base, other; + mmbuffer_t result = {NULL, 0}; + xpparam_t xpp = {XDF_NEED_MINIMAL}; + + if (handle_file(path, NULL, rr_path(name, "thisimage")) < 0) + return 1; + + if (read_mmfile(&cur, rr_path(name, "thisimage")) || + read_mmfile(&base, rr_path(name, "preimage")) || + read_mmfile(&other, rr_path(name, "postimage"))) + return 1; + ret = xdl_merge(&base, &cur, "", &other, "", + &xpp, XDL_MERGE_ZEALOUS, &result); + if (!ret) { + FILE *f = fopen(path, "w"); + if (!f) + return error("Could not write to %s", path); + fwrite(result.ptr, result.size, 1, f); + fclose(f); + } + + free(cur.ptr); + free(base.ptr); + free(other.ptr); + free(result.ptr); + + return ret; +} + +static struct lock_file index_lock; + +static int update_paths(struct path_list *update) +{ + int i; + int fd = hold_locked_index(&index_lock, 0); + int status = 0; + + if (fd < 0) + return -1; + + for (i = 0; i < update->nr; i++) { + struct path_list_item *item = &update->items[i]; + if (add_file_to_cache(item->path, ADD_CACHE_IGNORE_ERRORS)) + status = -1; + } + + if (!status && active_cache_changed) { + if (write_cache(fd, active_cache, active_nr) || + commit_locked_index(&index_lock)) + die("Unable to write new index file"); + } else if (fd >= 0) + rollback_lock_file(&index_lock); + return status; +} + +static int do_plain_rerere(struct path_list *rr, int fd) +{ + struct path_list conflict = { NULL, 0, 0, 1 }; + struct path_list update = { NULL, 0, 0, 1 }; + int i; + + find_conflict(&conflict); + + /* + * MERGE_RR records paths with conflicts immediately after merge + * failed. Some of the conflicted paths might have been hand resolved + * in the working tree since then, but the initial run would catch all + * and register their preimages. + */ + + for (i = 0; i < conflict.nr; i++) { + const char *path = conflict.items[i].path; + if (!path_list_has_path(rr, path)) { + unsigned char sha1[20]; + char *hex; + int ret; + ret = handle_file(path, sha1, NULL); + if (ret < 1) + continue; + hex = xstrdup(sha1_to_hex(sha1)); + path_list_insert(path, rr)->util = hex; + if (mkdir(git_path("rr-cache/%s", hex), 0755)) + continue;; + handle_file(path, NULL, rr_path(hex, "preimage")); + fprintf(stderr, "Recorded preimage for '%s'\n", path); + } + } + + /* + * Now some of the paths that had conflicts earlier might have been + * hand resolved. Others may be similar to a conflict already that + * was resolved before. + */ + + for (i = 0; i < rr->nr; i++) { + int ret; + const char *path = rr->items[i].path; + const char *name = (const char *)rr->items[i].util; + + if (has_resolution(name)) { + if (!merge(name, path)) { + fprintf(stderr, "Resolved '%s' using " + "previous resolution.\n", path); + if (rerere_autoupdate) + path_list_insert(path, &update); + goto mark_resolved; + } + } + + /* Let's see if we have resolved it. */ + ret = handle_file(path, NULL, NULL); + if (ret) + continue; + + fprintf(stderr, "Recorded resolution for '%s'.\n", path); + copy_file(rr_path(name, "postimage"), path, 0666); + mark_resolved: + rr->items[i].util = NULL; + } + + if (update.nr) + update_paths(&update); + + return write_rr(rr, fd); +} + +static int git_rerere_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "rerere.enabled")) + rerere_enabled = git_config_bool(var, value); + else if (!strcmp(var, "rerere.autoupdate")) + rerere_autoupdate = git_config_bool(var, value); + else + return git_default_config(var, value, cb); + return 0; +} + +static int is_rerere_enabled(void) +{ + struct stat st; + const char *rr_cache; + int rr_cache_exists; + + if (!rerere_enabled) + return 0; + + rr_cache = git_path("rr-cache"); + rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode); + if (rerere_enabled < 0) + return rr_cache_exists; + + if (!rr_cache_exists && + (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache))) + die("Could not create directory %s", rr_cache); + return 1; +} + +int setup_rerere(struct path_list *merge_rr) +{ + int fd; + + git_config(git_rerere_config, NULL); + if (!is_rerere_enabled()) + return -1; + + merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR")); + fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1); + read_rr(merge_rr); + return fd; +} + +int rerere(void) +{ + struct path_list merge_rr = { NULL, 0, 0, 1 }; + int fd; + + fd = setup_rerere(&merge_rr); + if (fd < 0) + return 0; + return do_plain_rerere(&merge_rr, fd); +} diff --git a/rerere.h b/rerere.h new file mode 100644 index 0000000000..35b0fa86a3 --- /dev/null +++ b/rerere.h @@ -0,0 +1,9 @@ +#ifndef RERERE_H +#define RERERE_H + +#include "path-list.h" + +extern int setup_rerere(struct path_list *); +extern int rerere(void); + +#endif -- cgit v1.3 From 1b1dd23f2d6a707b7077cdf6bc6d4055bd0bfb7d Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Sun, 13 Jul 2008 15:36:15 +0200 Subject: Make usage strings dash-less When you misuse a git command, you are shown the usage string. But this is currently shown in the dashed form. So if you just copy what you see, it will not work, when the dashed form is no longer supported. This patch makes git commands show the dash-less version. For shell scripts that do not specify OPTIONS_SPEC, git-sh-setup.sh generates a dash-less usage string now. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- builtin-add.c | 2 +- builtin-apply.c | 2 +- builtin-archive.c | 2 +- builtin-blame.c | 2 +- builtin-branch.c | 8 ++++---- builtin-cat-file.c | 4 ++-- builtin-check-attr.c | 2 +- builtin-checkout-index.c | 2 +- builtin-clean.c | 2 +- builtin-clone.c | 2 +- builtin-commit.c | 4 ++-- builtin-config.c | 2 +- builtin-count-objects.c | 2 +- builtin-describe.c | 2 +- builtin-diff-files.c | 2 +- builtin-diff-index.c | 2 +- builtin-diff-tree.c | 2 +- builtin-diff.c | 2 +- builtin-fast-export.c | 2 +- builtin-fetch-pack.c | 2 +- builtin-fetch.c | 2 +- builtin-fmt-merge-msg.c | 2 +- builtin-for-each-ref.c | 2 +- builtin-fsck.c | 2 +- builtin-gc.c | 2 +- builtin-grep.c | 2 +- builtin-init-db.c | 2 +- builtin-log.c | 2 +- builtin-ls-files.c | 2 +- builtin-ls-remote.c | 2 +- builtin-ls-tree.c | 2 +- builtin-mailinfo.c | 2 +- builtin-mailsplit.c | 2 +- builtin-merge-base.c | 2 +- builtin-mv.c | 2 +- builtin-name-rev.c | 2 +- builtin-pack-refs.c | 2 +- builtin-prune-packed.c | 2 +- builtin-prune.c | 2 +- builtin-push.c | 2 +- builtin-reflog.c | 6 +++--- builtin-rerere.c | 2 +- builtin-reset.c | 4 ++-- builtin-rev-list.c | 2 +- builtin-rev-parse.c | 2 +- builtin-revert.c | 4 ++-- builtin-rm.c | 2 +- builtin-send-pack.c | 2 +- builtin-shortlog.c | 2 +- builtin-show-branch.c | 2 +- builtin-symbolic-ref.c | 2 +- builtin-tag.c | 8 ++++---- builtin-tar-tree.c | 2 +- builtin-update-index.c | 2 +- builtin-update-ref.c | 4 ++-- builtin-upload-archive.c | 6 +++--- builtin-verify-tag.c | 2 +- builtin-write-tree.c | 2 +- daemon.c | 2 +- fast-import.c | 2 +- git-am.sh | 6 +++--- git-archimport.perl | 4 ++-- git-cvsexportcommit.perl | 2 +- git-cvsimport.perl | 2 +- git-cvsserver.perl | 2 +- git-instaweb.sh | 2 +- git-merge.sh | 4 ++-- git-pull.sh | 2 +- git-quiltimport.sh | 2 +- git-relink.perl | 2 +- git-repack.sh | 2 +- git-send-email.perl | 2 +- git-sh-setup.sh | 7 ++++--- git-svn.perl | 2 +- hash-object.c | 2 +- help.c | 2 +- http-push.c | 2 +- index-pack.c | 2 +- pack-redundant.c | 2 +- update-server-info.c | 2 +- 80 files changed, 102 insertions(+), 101 deletions(-) (limited to 'builtin-commit.c') diff --git a/builtin-add.c b/builtin-add.c index 9930cf53f5..bf13aa3ad6 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -16,7 +16,7 @@ #include "parse-options.h" static const char * const builtin_add_usage[] = { - "git-add [options] [--] ...", + "git add [options] [--] ...", NULL }; static int patch_interactive = 0, add_interactive = 0; diff --git a/builtin-apply.c b/builtin-apply.c index d13313f105..e15471b5b6 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -46,7 +46,7 @@ static const char *fake_ancestor; static int line_termination = '\n'; static unsigned long p_context = ULONG_MAX; static const char apply_usage[] = -"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; +"git apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; static enum ws_error_action { nowarn_ws_error, diff --git a/builtin-archive.c b/builtin-archive.c index c2e0c1ea5a..5cca460129 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -13,7 +13,7 @@ #include "attr.h" static const char archive_usage[] = \ -"git-archive --format= [--prefix=/] [--verbose] [] [path...]"; +"git archive --format= [--prefix=/] [--verbose] [] [path...]"; static struct archiver_desc { diff --git a/builtin-blame.c b/builtin-blame.c index b451f6c64d..91850a53e1 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -20,7 +20,7 @@ #include "mailmap.h" static char blame_usage[] = -"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" +"git blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S ] [-M] [-C] [-C] [--contents ] [--incremental] [commit] [--] file\n" " -c Use the same output mode as git-annotate (Default: off)\n" " -b Show blank SHA-1 for boundary commits (Default: off)\n" " -l Show long commit SHA1 (Default: off)\n" diff --git a/builtin-branch.c b/builtin-branch.c index d279702ba9..5cc3771ddd 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -15,10 +15,10 @@ #include "branch.h" static const char * const builtin_branch_usage[] = { - "git-branch [options] [-r | -a] [--merged | --no-merged]", - "git-branch [options] [-l] [-f] []", - "git-branch [options] [-r] (-d | -D) ", - "git-branch [options] (-m | -M) [] ", + "git branch [options] [-r | -a] [--merged | --no-merged]", + "git branch [options] [-l] [-f] []", + "git branch [options] [-r] (-d | -D) ", + "git branch [options] (-m | -M) [] ", NULL }; diff --git a/builtin-cat-file.c b/builtin-cat-file.c index 880e75af5e..7441a56acd 100644 --- a/builtin-cat-file.c +++ b/builtin-cat-file.c @@ -202,8 +202,8 @@ static int batch_objects(int print_contents) } static const char * const cat_file_usage[] = { - "git-cat-file [-t|-s|-e|-p|] ", - "git-cat-file [--batch|--batch-check] < ", + "git cat-file [-t|-s|-e|-p|] ", + "git cat-file [--batch|--batch-check] < ", NULL }; diff --git a/builtin-check-attr.c b/builtin-check-attr.c index 6afdfa10a1..cb783fc77e 100644 --- a/builtin-check-attr.c +++ b/builtin-check-attr.c @@ -4,7 +4,7 @@ #include "quote.h" static const char check_attr_usage[] = -"git-check-attr attr... [--] pathname..."; +"git check-attr attr... [--] pathname..."; int cmd_check_attr(int argc, const char **argv, const char *prefix) { diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index eb1fc9aa6f..71ebabf990 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -154,7 +154,7 @@ static void checkout_all(const char *prefix, int prefix_length) } static const char checkout_cache_usage[] = -"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]|all] [--prefix=] [--temp] [--] ..."; +"git checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]|all] [--prefix=] [--temp] [--] ..."; static struct lock_file lock_file; diff --git a/builtin-clean.c b/builtin-clean.c index 80a7ff9ae4..48bf29f40a 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -15,7 +15,7 @@ static int force = -1; /* unset */ static const char *const builtin_clean_usage[] = { - "git-clean [-d] [-f] [-n] [-q] [-x | -X] [--] ...", + "git clean [-d] [-f] [-n] [-q] [-x | -X] [--] ...", NULL }; diff --git a/builtin-clone.c b/builtin-clone.c index ec36209600..8112716c10 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -29,7 +29,7 @@ * */ static const char * const builtin_clone_usage[] = { - "git-clone [options] [--] []", + "git clone [options] [--] []", NULL }; diff --git a/builtin-commit.c b/builtin-commit.c index 745c11e773..41cf5f2dc2 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -25,12 +25,12 @@ #include "unpack-trees.h" static const char * const builtin_commit_usage[] = { - "git-commit [options] [--] ...", + "git commit [options] [--] ...", NULL }; static const char * const builtin_status_usage[] = { - "git-status [options] [--] ...", + "git status [options] [--] ...", NULL }; diff --git a/builtin-config.c b/builtin-config.c index 39f63d7b10..0cf191a112 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -3,7 +3,7 @@ #include "color.h" static const char git_config_set_usage[] = -"git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]"; +"git config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int | --bool-or-int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list | --get-color var [default] | --get-colorbool name [stdout-is-tty]"; static char *key; static regex_t *key_regexp; diff --git a/builtin-count-objects.c b/builtin-count-objects.c index f00306fb67..91b5487478 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -67,7 +67,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, } static char const * const count_objects_usage[] = { - "git-count-objects [-v]", + "git count-objects [-v]", NULL }; diff --git a/builtin-describe.c b/builtin-describe.c index e515f9ca9b..5dabca950d 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -10,7 +10,7 @@ #define MAX_TAGS (FLAG_BITS - 1) static const char * const describe_usage[] = { - "git-describe [options] *", + "git describe [options] *", NULL }; diff --git a/builtin-diff-files.c b/builtin-diff-files.c index 384d871263..9bf10bb37e 100644 --- a/builtin-diff-files.c +++ b/builtin-diff-files.c @@ -10,7 +10,7 @@ #include "builtin.h" static const char diff_files_usage[] = -"git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [] [...]" +"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [] [...]" COMMON_DIFF_OPTIONS_HELP; int cmd_diff_files(int argc, const char **argv, const char *prefix) diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 2f44ebfcdd..17d851b29e 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -5,7 +5,7 @@ #include "builtin.h" static const char diff_cache_usage[] = -"git-diff-index [-m] [--cached] " +"git diff-index [-m] [--cached] " "[] [...]" COMMON_DIFF_OPTIONS_HELP; diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 9d2a48fd68..415cb1612f 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -53,7 +53,7 @@ static int diff_tree_stdin(char *line) } static const char diff_tree_usage[] = -"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " +"git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " "[] [] [...]\n" " -r diff recursively\n" " --root include the initial commit as diff against /dev/null\n" diff --git a/builtin-diff.c b/builtin-diff.c index 4c289e798a..faaa85a1d4 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -21,7 +21,7 @@ struct blobinfo { }; static const char builtin_diff_usage[] = -"git-diff {0,2} -- *"; +"git diff {0,2} -- *"; static void stuff_change(struct diff_options *opt, unsigned old_mode, unsigned new_mode, diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 75132bacfa..76f3167276 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -18,7 +18,7 @@ #include "parse-options.h" static const char *fast_export_usage[] = { - "git-fast-export [rev-list-opts]", + "git fast-export [rev-list-opts]", NULL }; diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 1ea7040639..273239af3b 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -18,7 +18,7 @@ static struct fetch_pack_args args = { }; static const char fetch_pack_usage[] = -"git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=] [--depth=] [--no-progress] [-v] [:] [...]"; +"git fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=] [--depth=] [--no-progress] [-v] [:] [...]"; #define COMPLETE (1U << 0) #define COMMON (1U << 1) diff --git a/builtin-fetch.c b/builtin-fetch.c index 97fdc51e31..61de50a020 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -12,7 +12,7 @@ #include "parse-options.h" static const char * const builtin_fetch_usage[] = { - "git-fetch [options] [ ...]", + "git fetch [options] [ ...]", NULL }; diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index b892621ab5..b34b01ff51 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -6,7 +6,7 @@ #include "tag.h" static const char *fmt_merge_msg_usage = - "git-fmt-merge-msg [--log] [--no-log] [--file ]"; + "git fmt-merge-msg [--log] [--no-log] [--file ]"; static int merge_summary; diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index fef93d7488..76282ad791 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -831,7 +831,7 @@ int opt_parse_sort(const struct option *opt, const char *arg, int unset) } static char const * const for_each_ref_usage[] = { - "git-for-each-ref [options] []", + "git for-each-ref [options] []", NULL }; diff --git a/builtin-fsck.c b/builtin-fsck.c index b0f9648f86..7326dc33a5 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -539,7 +539,7 @@ static int fsck_cache_tree(struct cache_tree *it) } static char const * const fsck_usage[] = { - "git-fsck [options] [...]", + "git fsck [options] [...]", NULL }; diff --git a/builtin-gc.c b/builtin-gc.c index f5625bb9fb..fac200e0b0 100644 --- a/builtin-gc.c +++ b/builtin-gc.c @@ -18,7 +18,7 @@ #define FAILED_RUN "failed to run %s" static const char * const builtin_gc_usage[] = { - "git-gc [options]", + "git gc [options]", NULL }; diff --git a/builtin-grep.c b/builtin-grep.c index ef299108f5..0cac39590d 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -495,7 +495,7 @@ static int grep_object(struct grep_opt *opt, const char **paths, } static const char builtin_grep_usage[] = -"git-grep