void prime_cache_tree(struct index_state *istate, struct tree *tree) { cache_tree_free(&istate->cache_tree); istate->cache_tree = cache_tree(); prime_cache_tree_rec(istate->cache_tree, tree); istate->cache_changed |= CACHE_TREE_CHANGED; }
static int is_index_unchanged(void) { unsigned char head_sha1[20]; struct commit *head_commit; if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL)) return error(_("Could not resolve HEAD commit\n")); head_commit = lookup_commit(head_sha1); /* * If head_commit is NULL, check_commit, called from * lookup_commit, would have indicated that head_commit is not * a commit object already. parse_commit() will return failure * without further complaints in such a case. Otherwise, if * the commit is invalid, parse_commit() will complain. So * there is nothing for us to say here. Just return failure. */ if (parse_commit(head_commit)) return -1; if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree)) if (cache_tree_update(&the_index, 0)) return error(_("Unable to update cache tree\n")); return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash); }
int update_main_cache_tree(int flags) { if (!the_index.cache_tree) the_index.cache_tree = cache_tree(); return cache_tree_update(the_index.cache_tree, the_index.cache, the_index.cache_nr, flags); }
struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; output(o, 0, "There are unmerged index entries:"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) output(o, 0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); } return NULL; } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); return result; }
char *write_tree_from_memory(struct merge_options *o) { struct cache_tree *it; char root_id[41]; if (unmerged_index(o->index)) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < o->index->cache_nr; i++) { struct cache_entry *ce = o->index->cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), (int)ce_namelen(ce), ce->name); } g_assert(0); } /* if (!active_cache_tree) */ it = cache_tree(); if (cache_tree_update(it, o->index->cache, o->index->cache_nr, 0, 0, commit_trees_cb) < 0) { g_warning("error building trees"); cache_tree_free (&it); return NULL; } rawdata_to_hex(it->sha1, root_id, 20); cache_tree_free (&it); return g_strdup(root_id); }
/* Prepare tree display for inclusion in the article header. */ void init_tree() { ARTICLE *thread; SUBJECT *sp; int num; while (max_line >= 0) /* free any previous tree data */ free(tree_lines[max_line--]); if (!(tree_article = curr_artp) || !tree_article->subj) return; if (!(thread = tree_article->subj->thread)) return; /* Enumerate our subjects for display */ sp = thread->subj; num = 0; do { sp->misc = num++; sp = sp->thread_link; } while (sp != thread->subj); max_depth = max_line = my_depth = my_line = node_line_cnt = 0; find_depth(thread, 0); if (max_depth <= 5) { first_depth = 0; } else { if (my_depth+2 > max_depth) { first_depth = max_depth - 5; } else if ((first_depth = my_depth - 3) < 0) { first_depth = 0; } max_depth = first_depth + 5; } if (--max_line < max_tree_lines) { first_line = 0; } else { if (my_line + max_tree_lines/2 > max_line) { first_line = max_line - (max_tree_lines-1); } else if ((first_line = my_line - (max_tree_lines-1)/2) < 0) { first_line = 0; } max_line = first_line + max_tree_lines-1; } str = tree_buff; /* initialize first line's data */ *str++ = ' '; node_on_line = FALSE; line_num = 0; /* cache our portion of the tree */ cache_tree(thread, 0, tree_indent); max_depth = (max_depth-first_depth) * 5; /* turn depth into char width */ max_line -= first_line; /* turn max_line into count */ /* shorten tree if lower lines aren't visible */ if (node_line_cnt < max_line) { max_line = node_line_cnt + 1; } }
struct tree *write_tree_from_memory(struct merge_options *o) { struct tree *result = NULL; if (unmerged_cache()) { int i; fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), (int)ce_namelen(ce), ce->name); } die("Bug in merge-recursive.c"); } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); return result; }
static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) { struct tree_desc desc; struct name_entry entry; int cnt; hashcpy(it->sha1, tree->object.sha1); init_tree_desc(&desc, tree->buffer, tree->size); cnt = 0; while (tree_entry(&desc, &entry)) { if (!S_ISDIR(entry.mode)) cnt++; else { struct cache_tree_sub *sub; struct tree *subtree = lookup_tree(entry.sha1); if (!subtree->object.parsed) parse_tree(subtree); sub = cache_tree_sub(it, entry.path); sub->cache_tree = cache_tree(); prime_cache_tree_rec(sub->cache_tree, subtree); cnt += sub->cache_tree->entry_count; } } it->entry_count = cnt; }
int update_main_cache_tree(int flags) { if (!the_index.cache_tree) the_index.cache_tree = cache_tree(); return cache_tree_update(the_index.cache_tree, (const struct cache_entry * const *)the_index.cache, the_index.cache_nr, flags); }
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix) { int entries, was_valid, newfd; struct lock_file *lock_file; /* * We can't free this memory, it becomes part of a linked list * parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 1); entries = read_cache(); if (entries < 0) return WRITE_TREE_UNREADABLE_INDEX; if (flags & WRITE_TREE_IGNORE_CACHE_TREE) cache_tree_free(&(active_cache_tree)); if (!active_cache_tree) active_cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(active_cache_tree); if (!was_valid) { int missing_ok = flags & WRITE_TREE_MISSING_OK; if (cache_tree_update(active_cache_tree, active_cache, active_nr, missing_ok, 0) < 0) return WRITE_TREE_UNMERGED_INDEX; if (0 <= newfd) { 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 * ends up using the old index with unupdated cache-tree part * it misses the work we did here, but that is just a * performance penalty and not a big deal. */ } if (prefix) { struct cache_tree *subtree = cache_tree_find(active_cache_tree, prefix); if (!subtree) return WRITE_TREE_PREFIX_ERROR; hashcpy(sha1, subtree->sha1); } else hashcpy(sha1, active_cache_tree->sha1); if (0 <= newfd) rollback_lock_file(lock_file); return 0; }
int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix) { int entries, was_valid, newfd; struct lock_file *lock_file; /* * We can't free this memory, it becomes part of a linked list * parsed atexit() */ lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR); entries = read_index_from(index_state, index_path); if (entries < 0) return WRITE_TREE_UNREADABLE_INDEX; if (flags & WRITE_TREE_IGNORE_CACHE_TREE) cache_tree_free(&index_state->cache_tree); if (!index_state->cache_tree) index_state->cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(index_state->cache_tree); if (!was_valid) { if (cache_tree_update(index_state, flags) < 0) return WRITE_TREE_UNMERGED_INDEX; if (0 <= newfd) { if (!write_locked_index(index_state, lock_file, COMMIT_LOCK)) newfd = -1; } /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller * ends up using the old index with unupdated cache-tree part * it misses the work we did here, but that is just a * performance penalty and not a big deal. */ } if (prefix) { struct cache_tree *subtree; subtree = cache_tree_find(index_state->cache_tree, prefix); if (!subtree) return WRITE_TREE_PREFIX_ERROR; hashcpy(sha1, subtree->sha1); } else hashcpy(sha1, index_state->cache_tree->sha1); if (0 <= newfd) rollback_lock_file(lock_file); return 0; }
int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix) { int entries, was_valid; struct lock_file lock_file = LOCK_INIT; int ret = 0; hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR); entries = read_index_from(index_state, index_path, get_git_dir()); if (entries < 0) { ret = WRITE_TREE_UNREADABLE_INDEX; goto out; } if (flags & WRITE_TREE_IGNORE_CACHE_TREE) cache_tree_free(&index_state->cache_tree); if (!index_state->cache_tree) index_state->cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(index_state->cache_tree); if (!was_valid) { if (cache_tree_update(index_state, flags) < 0) { ret = WRITE_TREE_UNMERGED_INDEX; goto out; } write_locked_index(index_state, &lock_file, COMMIT_LOCK); /* Not being able to write is fine -- we are only interested * in updating the cache-tree part, and if the next caller * ends up using the old index with unupdated cache-tree part * it misses the work we did here, but that is just a * performance penalty and not a big deal. */ } if (prefix) { struct cache_tree *subtree; subtree = cache_tree_find(index_state->cache_tree, prefix); if (!subtree) { ret = WRITE_TREE_PREFIX_ERROR; goto out; } oidcpy(oid, &subtree->oid); } else oidcpy(oid, &index_state->cache_tree->oid); out: rollback_lock_file(&lock_file); return ret; }
static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) { const char *buf = *buffer; unsigned long size = *size_p; const char *cp; char *ep; struct cache_tree *it; int i, subtree_nr; it = NULL; /* skip name, but make sure name exists */ while (size && *buf) { size--; buf++; } if (!size) goto free_return; buf++; size--; it = cache_tree(); cp = buf; it->entry_count = strtol(cp, &ep, 10); if (cp == ep) goto free_return; cp = ep; subtree_nr = strtol(cp, &ep, 10); if (cp == ep) goto free_return; while (size && *buf && *buf != '\n') { size--; buf++; } if (!size) goto free_return; buf++; size--; if (0 <= it->entry_count) { if (size < 20) goto free_return; hashcpy(it->sha1, (const unsigned char*)buf); buf += 20; size -= 20; } #if DEBUG if (0 <= it->entry_count) fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n", *buffer, it->entry_count, subtree_nr, sha1_to_hex(it->sha1)); else fprintf(stderr, "cache-tree <%s> (%d subtrees) invalid\n", *buffer, subtree_nr); #endif /* * Just a heuristic -- we do not add directories that often but * we do not want to have to extend it immediately when we do, * hence +2. */ it->subtree_alloc = subtree_nr + 2; it->down = xcalloc(it->subtree_alloc, sizeof(struct cache_tree_sub *)); for (i = 0; i < subtree_nr; i++) { /* read each subtree */ struct cache_tree *sub; struct cache_tree_sub *subtree; const char *name = buf; sub = read_one(&buf, &size); if (!sub) goto free_return; subtree = cache_tree_sub(it, name); subtree->cache_tree = sub; } if (subtree_nr != it->subtree_nr) die("cache-tree: internal error"); *buffer = buf; *size_p = size; return it; free_return: cache_tree_free(&it); return NULL; }
static int update_one(struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen, int missing_ok, int dryrun) { struct strbuf buffer; int i; if (0 <= it->entry_count && has_sha1_file(it->sha1)) return it->entry_count; /* * We first scan for subtrees and update them; we start by * marking existing subtrees -- the ones that are unmarked * should not be in the result. */ for (i = 0; i < it->subtree_nr; i++) it->down[i]->used = 0; /* * Find the subtrees and update them. */ for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, sublen, subcnt; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (!slash) continue; /* * a/bbb/c (base = a/, slash = /c) * ==> * path+baselen = bbb/c, sublen = 3 */ sublen = slash - (path + baselen); sub = find_subtree(it, path + baselen, sublen, 1); if (!sub->cache_tree) sub->cache_tree = cache_tree(); subcnt = update_one(sub->cache_tree, cache + i, entries - i, path, baselen + sublen + 1, missing_ok, dryrun); if (subcnt < 0) return subcnt; i += subcnt - 1; sub->used = 1; } discard_unused_subtrees(it); /* * Then write out the tree object for this level. */ strbuf_init(&buffer, 8192); for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, entlen; const unsigned char *sha1; unsigned mode; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = find_subtree(it, path + baselen, entlen, 0); if (!sub) die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); i += sub->cache_tree->entry_count - 1; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) return error("invalid object %06o %s for '%.*s'", mode, sha1_to_hex(sha1), entlen+baselen, path); if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ strbuf_grow(&buffer, entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); strbuf_add(&buffer, sha1, 20); #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } if (dryrun) hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) { strbuf_release(&buffer); return -1; } strbuf_release(&buffer); it->entry_count = i; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, sha1_to_hex(it->sha1)); #endif return i; }
static int prepare_to_commit(const char *index_file, const char *prefix) { struct stat statbuf; int commitable, saved_color_setting; struct strbuf sb; char *buffer; FILE *fp; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; strbuf_init(&sb, 0); if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); if (strbuf_read(&sb, 0, 0) < 0) die("could not read log from standard input"); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die("could not read log file '%s': %s", logfile, strerror(errno)); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); if (!buffer || buffer[2] == '\0') die("commit has empty message"); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die("could not read MERGE_MSG: %s", strerror(errno)); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die("could not read SQUASH_MSG: %s", strerror(errno)); hook_arg1 = "squash"; } else if (template_file && !stat(template_file, &statbuf)) { if (strbuf_read_file(&sb, template_file, 0) < 0) die("could not read %s: %s", template_file, strerror(errno)); hook_arg1 = "template"; } /* * This final case does not modify the template message, * it just sets the argument to the prepare-commit-msg hook. */ else if (in_merge) hook_arg1 = "merge"; fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) die("could not open %s", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); if (signoff) { struct strbuf sob; int i; strbuf_init(&sob, 0); strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) ; /* do nothing */ if (prefixcmp(sb.buf + i, sob.buf)) { if (prefixcmp(sb.buf + i, sign_off_header)) strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); } strbuf_release(&sob); } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) die("could not write commit template: %s", strerror(errno)); strbuf_release(&sb); determine_author_info(); /* This checks if committer ident is explicitly given */ git_committer_info(0); if (use_editor) { char *author_ident; const char *committer_ident; if (in_merge) fprintf(fp, "#\n" "# It looks like you may be committing a MERGE.\n" "# If this is not correct, please remove the file\n" "# %s\n" "# and try again.\n" "#\n", git_path("MERGE_HEAD")); fprintf(fp, "\n" "# Please enter the commit message for your changes.\n" "# (Comment lines starting with '#' will "); if (cleanup_mode == CLEANUP_ALL) fprintf(fp, "not be included)\n"); else /* CLEANUP_SPACE, that is. */ fprintf(fp, "be kept.\n" "# You can remove them yourself if you want to)\n"); if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); author_ident = xstrdup(fmt_name(author_name, author_email)); committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL")); if (strcmp(author_ident, committer_ident)) fprintf(fp, "%s" "# Author: %s\n", ident_shown++ ? "" : "#\n", author_ident); free(author_ident); if (!user_ident_explicitly_given) fprintf(fp, "%s" "# Committer: %s\n", ident_shown++ ? "" : "#\n", committer_ident); if (ident_shown) fprintf(fp, "#\n"); saved_color_setting = wt_status_use_color; wt_status_use_color = 0; commitable = run_status(fp, index_file, prefix, 1); wt_status_use_color = saved_color_setting; } else { struct rev_info rev; unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die("Cannot read index"); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else { init_revisions(&rev, ""); rev.abbrev = 0; setup_revisions(0, NULL, &rev, parent); DIFF_OPT_SET(&rev.diffopt, QUIET); DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS); run_diff_index(&rev, 1 /* cached */); commitable = !!DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES); } } fclose(fp); if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0); unlink(commit_editmsg); return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (!active_cache_tree) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { error("Error building trees"); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { index, NULL }; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); launch_editor(git_path(commit_editmsg), NULL, env); } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
static int merge_working_tree(const struct checkout_opts *opts, struct branch_info *old_branch_info, struct branch_info *new_branch_info, int *writeout_error) { int ret; struct lock_file lock_file = LOCK_INIT; hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR); if (read_cache_preload(NULL) < 0) return error(_("index file corrupt")); resolve_undo_clear(); if (opts->force) { ret = reset_tree(get_commit_tree(new_branch_info->commit), opts, 1, writeout_error); if (ret) return ret; } else { struct tree_desc trees[2]; struct tree *tree; struct unpack_trees_options topts; memset(&topts, 0, sizeof(topts)); topts.head_idx = -1; topts.src_index = &the_index; topts.dst_index = &the_index; setup_unpack_trees_porcelain(&topts, "checkout"); refresh_cache(REFRESH_QUIET); if (unmerged_cache()) { error(_("you need to resolve your current index first")); return 1; } /* 2-way merge to the new branch */ topts.initial_checkout = is_cache_unborn(); topts.update = 1; topts.merge = 1; topts.gently = opts->merge && old_branch_info->commit; topts.verbose_update = opts->show_progress; topts.fn = twoway_merge; if (opts->overwrite_ignore) { topts.dir = xcalloc(1, sizeof(*topts.dir)); topts.dir->flags |= DIR_SHOW_IGNORED; setup_standard_excludes(topts.dir); } tree = parse_tree_indirect(old_branch_info->commit ? &old_branch_info->commit->object.oid : the_hash_algo->empty_tree); init_tree_desc(&trees[0], tree->buffer, tree->size); tree = parse_tree_indirect(&new_branch_info->commit->object.oid); init_tree_desc(&trees[1], tree->buffer, tree->size); ret = unpack_trees(2, trees, &topts); clear_unpack_trees_porcelain(&topts); if (ret == -1) { /* * Unpack couldn't do a trivial merge; either * give up or do a real merge, depending on * whether the merge flag was used. */ struct tree *result; struct tree *work; struct merge_options o; if (!opts->merge) return 1; /* * Without old_branch_info->commit, the below is the same as * the two-tree unpack we already tried and failed. */ if (!old_branch_info->commit) return 1; /* Do more real merge */ /* * We update the index fully, then write the * tree from the index, then merge the new * branch with the current tree, with the old * branch as the base. Then we reset the index * (but not the working tree) to the new * branch, leaving the working tree as the * merged version, but skipping unmerged * entries in the index. */ add_files_to_cache(NULL, NULL, 0); /* * NEEDSWORK: carrying over local changes * when branches have different end-of-line * normalization (or clean+smudge rules) is * a pain; plumb in an option to set * o.renormalize? */ init_merge_options(&o, the_repository); o.verbosity = 0; work = write_tree_from_memory(&o); ret = reset_tree(get_commit_tree(new_branch_info->commit), opts, 1, writeout_error); if (ret) return ret; o.ancestor = old_branch_info->name; o.branch1 = new_branch_info->name; o.branch2 = "local"; ret = merge_trees(&o, get_commit_tree(new_branch_info->commit), work, get_commit_tree(old_branch_info->commit), &result); if (ret < 0) exit(128); ret = reset_tree(get_commit_tree(new_branch_info->commit), opts, 0, writeout_error); strbuf_release(&o.obuf); if (ret) return ret; } } if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree)) cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) die(_("unable to write new index file")); if (!opts->force && !opts->quiet) show_local_changes(&new_branch_info->commit->object, &opts->diff_options); return 0; }
static void * gen(gclass_t * cl, int lvl) { cache_tree(cl, lvl); assert(cl->max_freq); return gensub(cl, random() % cl->max_freq); }
static int prepare_to_commit(const char *index_file, const char *prefix, struct wt_status *s) { struct stat statbuf; int commitable, saved_color_setting; struct strbuf sb = STRBUF_INIT; char *buffer; FILE *fp; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die("could not lookup commit %s", squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); if (strbuf_read(&sb, 0, 0) < 0) die_errno("could not read log from standard input"); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno("could not read log file '%s'", logfile); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); if (!buffer || buffer[2] == '\0') die("commit has empty message"); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die("could not lookup commit %s", fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die_errno("could not read MERGE_MSG"); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die_errno("could not read SQUASH_MSG"); hook_arg1 = "squash"; } else if (template_file && !stat(template_file, &statbuf)) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno("could not read '%s'", template_file); hook_arg1 = "template"; } /* * This final case does not modify the template message, * it just sets the argument to the prepare-commit-msg hook. */ else if (in_merge) hook_arg1 = "merge"; if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) die_errno("could not open '%s'", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); if (signoff) { struct strbuf sob = STRBUF_INIT; int i; strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) ; /* do nothing */ if (prefixcmp(sb.buf + i, sob.buf)) { if (!i || !ends_rfc2822_footer(&sb)) strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); } strbuf_release(&sob); } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) die_errno("could not write commit template"); strbuf_release(&sb); determine_author_info(); /* This checks if committer ident is explicitly given */ git_committer_info(0); if (use_editor && include_status) { char *author_ident; const char *committer_ident; if (in_merge) fprintf(fp, "#\n" "# It looks like you may be committing a MERGE.\n" "# If this is not correct, please remove the file\n" "# %s\n" "# and try again.\n" "#\n", git_path("MERGE_HEAD")); fprintf(fp, "\n" "# Please enter the commit message for your changes."); if (cleanup_mode == CLEANUP_ALL) fprintf(fp, " Lines starting\n" "# with '#' will be ignored, and an empty" " message aborts the commit.\n"); else /* CLEANUP_SPACE, that is. */ fprintf(fp, " Lines starting\n" "# with '#' will be kept; you may remove them" " yourself if you want to.\n" "# An empty message aborts the commit.\n"); if (only_include_assumed) fprintf(fp, "# %s\n", only_include_assumed); author_ident = xstrdup(fmt_name(author_name, author_email)); committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL")); if (strcmp(author_ident, committer_ident)) fprintf(fp, "%s" "# Author: %s\n", ident_shown++ ? "" : "#\n", author_ident); free(author_ident); if (!user_ident_sufficiently_given()) fprintf(fp, "%s" "# Committer: %s\n", ident_shown++ ? "" : "#\n", committer_ident); if (ident_shown) fprintf(fp, "#\n"); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die("Cannot read index"); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } fclose(fp); if (!commitable && !in_merge && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(empty_amend_advice, stderr); return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (!active_cache_tree) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { error("Error building trees"); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { NULL }; env[0] = index; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); if (launch_editor(git_path(commit_editmsg), NULL, env)) { fprintf(stderr, "Please supply the message using either -m or -F option.\n"); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }
static int update_one(struct cache_tree *it, const struct cache_entry * const *cache, int entries, const char *base, int baselen, int *skip_count, int flags) { struct strbuf buffer; int missing_ok = flags & WRITE_TREE_MISSING_OK; int dryrun = flags & WRITE_TREE_DRY_RUN; int to_invalidate = 0; int i; *skip_count = 0; if (0 <= it->entry_count && has_sha1_file(it->sha1)) return it->entry_count; /* * We first scan for subtrees and update them; we start by * marking existing subtrees -- the ones that are unmarked * should not be in the result. */ for (i = 0; i < it->subtree_nr; i++) it->down[i]->used = 0; /* * Find the subtrees and update them. */ i = 0; while (i < entries) { const struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, sublen, subcnt, subskip; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (!slash) { i++; continue; } /* * a/bbb/c (base = a/, slash = /c) * ==> * path+baselen = bbb/c, sublen = 3 */ sublen = slash - (path + baselen); sub = find_subtree(it, path + baselen, sublen, 1); if (!sub->cache_tree) sub->cache_tree = cache_tree(); subcnt = update_one(sub->cache_tree, cache + i, entries - i, path, baselen + sublen + 1, &subskip, flags); if (subcnt < 0) return subcnt; i += subcnt; sub->count = subcnt; /* to be used in the next loop */ *skip_count += subskip; sub->used = 1; } discard_unused_subtrees(it); /* * Then write out the tree object for this level. */ strbuf_init(&buffer, 8192); i = 0; while (i < entries) { const struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, entlen; const unsigned char *sha1; unsigned mode; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = find_subtree(it, path + baselen, entlen, 0); if (!sub) die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); i += sub->count; sha1 = sub->cache_tree->sha1; mode = S_IFDIR; if (sub->cache_tree->entry_count < 0) to_invalidate = 1; } else { sha1 = ce->sha1; mode = ce->ce_mode; entlen = pathlen - baselen; i++; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) { strbuf_release(&buffer); return error("invalid object %06o %s for '%.*s'", mode, sha1_to_hex(sha1), entlen+baselen, path); } /* * CE_REMOVE entries are removed before the index is * written to disk. Skip them to remain consistent * with the future on-disk index. */ if (ce->ce_flags & CE_REMOVE) { *skip_count = *skip_count + 1; continue; } /* * CE_INTENT_TO_ADD entries exist on on-disk index but * they are not part of generated trees. Invalidate up * to root to force cache-tree users to read elsewhere. */ if (ce->ce_flags & CE_INTENT_TO_ADD) { to_invalidate = 1; continue; } strbuf_grow(&buffer, entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); strbuf_add(&buffer, sha1, 20); #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } if (dryrun) hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) { strbuf_release(&buffer); return -1; } strbuf_release(&buffer); it->entry_count = to_invalidate ? -1 : i - *skip_count; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, sha1_to_hex(it->sha1)); #endif return i; }
void prime_cache_tree(struct cache_tree **it, struct tree *tree) { cache_tree_free(it); *it = cache_tree(); prime_cache_tree_rec(*it, tree); }
static int update_one(struct cache_tree *it, struct cache_entry **cache, int entries, const char *base, int baselen, int *skip_count, int flags) { struct strbuf buffer; int missing_ok = flags & WRITE_TREE_MISSING_OK; int dryrun = flags & WRITE_TREE_DRY_RUN; int repair = flags & WRITE_TREE_REPAIR; int to_invalidate = 0; int i; assert(!(dryrun && repair)); *skip_count = 0; if (0 <= it->entry_count && has_sha1_file(it->oid.hash)) return it->entry_count; /* * We first scan for subtrees and update them; we start by * marking existing subtrees -- the ones that are unmarked * should not be in the result. */ for (i = 0; i < it->subtree_nr; i++) it->down[i]->used = 0; /* * Find the subtrees and update them. */ i = 0; while (i < entries) { const struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub; const char *path, *slash; int pathlen, sublen, subcnt, subskip; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (!slash) { i++; continue; } /* * a/bbb/c (base = a/, slash = /c) * ==> * path+baselen = bbb/c, sublen = 3 */ sublen = slash - (path + baselen); sub = find_subtree(it, path + baselen, sublen, 1); if (!sub->cache_tree) sub->cache_tree = cache_tree(); subcnt = update_one(sub->cache_tree, cache + i, entries - i, path, baselen + sublen + 1, &subskip, flags); if (subcnt < 0) return subcnt; if (!subcnt) die("index cache-tree records empty sub-tree"); i += subcnt; sub->count = subcnt; /* to be used in the next loop */ *skip_count += subskip; sub->used = 1; } discard_unused_subtrees(it); /* * Then write out the tree object for this level. */ strbuf_init(&buffer, 8192); i = 0; while (i < entries) { const struct cache_entry *ce = cache[i]; struct cache_tree_sub *sub = NULL; const char *path, *slash; int pathlen, entlen; const struct object_id *oid; unsigned mode; int expected_missing = 0; int contains_ita = 0; int ce_missing_ok; path = ce->name; pathlen = ce_namelen(ce); if (pathlen <= baselen || memcmp(base, path, baselen)) break; /* at the end of this level */ slash = strchr(path + baselen, '/'); if (slash) { entlen = slash - (path + baselen); sub = find_subtree(it, path + baselen, entlen, 0); if (!sub) die("cache-tree.c: '%.*s' in '%s' not found", entlen, path + baselen, path); i += sub->count; oid = &sub->cache_tree->oid; mode = S_IFDIR; contains_ita = sub->cache_tree->entry_count < 0; if (contains_ita) { to_invalidate = 1; expected_missing = 1; } } else { oid = &ce->oid; mode = ce->ce_mode; entlen = pathlen - baselen; i++; } ce_missing_ok = mode == S_IFGITLINK || missing_ok || (repository_format_partial_clone && ce_skip_worktree(ce)); if (is_null_oid(oid) || (!ce_missing_ok && !has_object_file(oid))) { strbuf_release(&buffer); if (expected_missing) return -1; return error("invalid object %06o %s for '%.*s'", mode, oid_to_hex(oid), entlen+baselen, path); } /* * CE_REMOVE entries are removed before the index is * written to disk. Skip them to remain consistent * with the future on-disk index. */ if (ce->ce_flags & CE_REMOVE) { *skip_count = *skip_count + 1; continue; } /* * CE_INTENT_TO_ADD entries exist on on-disk index but * they are not part of generated trees. Invalidate up * to root to force cache-tree users to read elsewhere. */ if (!sub && ce_intent_to_add(ce)) { to_invalidate = 1; continue; } /* * "sub" can be an empty tree if all subentries are i-t-a. */ if (contains_ita && is_empty_tree_oid(oid)) continue; strbuf_grow(&buffer, entlen + 100); strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz); #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", mode, entlen, path + baselen); #endif } if (repair) { struct object_id oid; hash_object_file(buffer.buf, buffer.len, tree_type, &oid); if (has_object_file(&oid)) oidcpy(&it->oid, &oid); else to_invalidate = 1; } else if (dryrun) { hash_object_file(buffer.buf, buffer.len, tree_type, &it->oid); } else if (write_object_file(buffer.buf, buffer.len, tree_type, &it->oid)) { strbuf_release(&buffer); return -1; } strbuf_release(&buffer); it->entry_count = to_invalidate ? -1 : i - *skip_count; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", it->entry_count, it->subtree_nr, oid_to_hex(&it->oid)); #endif return i; }
/* * N-way merge "len" trees. Returns 0 on success, -1 on failure to manipulate the * resulting index, -2 on failure to reflect the changes to the work tree. * * CE_ADDED, CE_UNPACKED and CE_NEW_SKIP_WORKTREE are used internally */ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o) { int i, ret; static struct cache_entry *dfc; struct exclude_list el; if (len > MAX_UNPACK_TREES) die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES); memset(&state, 0, sizeof(state)); state.base_dir = ""; state.force = 1; state.quiet = 1; state.refresh_cache = 1; state.istate = &o->result; memset(&el, 0, sizeof(el)); if (!core_apply_sparse_checkout || !o->update) o->skip_sparse_checkout = 1; if (!o->skip_sparse_checkout) { char *sparse = git_pathdup("info/sparse-checkout"); if (add_excludes_from_file_to_list(sparse, "", 0, &el, 0) < 0) o->skip_sparse_checkout = 1; else o->el = ⪙ free(sparse); } memset(&o->result, 0, sizeof(o->result)); o->result.initialized = 1; o->result.timestamp.sec = o->src_index->timestamp.sec; o->result.timestamp.nsec = o->src_index->timestamp.nsec; o->result.version = o->src_index->version; o->result.split_index = o->src_index->split_index; if (o->result.split_index) o->result.split_index->refcount++; hashcpy(o->result.sha1, o->src_index->sha1); o->merge_size = len; mark_all_ce_unused(o->src_index); /* * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries */ if (!o->skip_sparse_checkout) mark_new_skip_worktree(o->el, o->src_index, 0, CE_NEW_SKIP_WORKTREE); if (!dfc) dfc = xcalloc(1, cache_entry_size(0)); o->df_conflict_entry = dfc; if (len) { const char *prefix = o->prefix ? o->prefix : ""; struct traverse_info info; setup_traverse_info(&info, prefix); info.fn = unpack_callback; info.data = o; info.show_all_errors = o->show_all_errors; info.pathspec = o->pathspec; if (o->prefix) { /* * Unpack existing index entries that sort before the * prefix the tree is spliced into. Note that o->merge * is always true in this case. */ while (1) { struct cache_entry *ce = next_cache_entry(o); if (!ce) break; if (ce_in_traverse_path(ce, &info)) break; if (unpack_index_entry(ce, o) < 0) goto return_failed; } } if (traverse_trees(len, t, &info) < 0) goto return_failed; } /* Any left-over entries in the index? */ if (o->merge) { while (1) { struct cache_entry *ce = next_cache_entry(o); if (!ce) break; if (unpack_index_entry(ce, o) < 0) goto return_failed; } } mark_all_ce_unused(o->src_index); if (o->trivial_merges_only && o->nontrivial_merge) { ret = unpack_failed(o, "Merge requires file-level merging"); goto done; } if (!o->skip_sparse_checkout) { int empty_worktree = 1; /* * Sparse checkout loop #2: set NEW_SKIP_WORKTREE on entries not in loop #1 * If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE * so apply_sparse_checkout() won't attempt to remove it from worktree */ mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE); ret = 0; for (i = 0; i < o->result.cache_nr; i++) { struct cache_entry *ce = o->result.cache[i]; /* * Entries marked with CE_ADDED in merged_entry() do not have * verify_absent() check (the check is effectively disabled * because CE_NEW_SKIP_WORKTREE is set unconditionally). * * Do the real check now because we have had * correct CE_NEW_SKIP_WORKTREE */ if (ce->ce_flags & CE_ADDED && verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) { if (!o->show_all_errors) goto return_failed; ret = -1; } if (apply_sparse_checkout(&o->result, ce, o)) { if (!o->show_all_errors) goto return_failed; ret = -1; } if (!ce_skip_worktree(ce)) empty_worktree = 0; } if (ret < 0) goto return_failed; /* * Sparse checkout is meant to narrow down checkout area * but it does not make sense to narrow down to empty working * tree. This is usually a mistake in sparse checkout rules. * Do not allow users to do that. */ if (o->result.cache_nr && empty_worktree) { ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory"); goto done; } } o->src_index = NULL; ret = check_updates(o) ? (-2) : 0; if (o->dst_index) { if (!ret) { if (!o->result.cache_tree) o->result.cache_tree = cache_tree(); if (!cache_tree_fully_valid(o->result.cache_tree)) cache_tree_update(&o->result, WRITE_TREE_SILENT | WRITE_TREE_REPAIR); } discard_index(o->dst_index); *o->dst_index = o->result; } else { discard_index(&o->result); } done: clear_exclude_list(&el); return ret; return_failed: if (o->show_all_errors) display_error_msgs(o); mark_all_ce_unused(o->src_index); ret = unpack_failed(o, NULL); if (o->exiting_early) ret = 0; goto done; }
static int prepare_to_commit(const char *index_file, const char *prefix, struct wt_status *s, struct strbuf *author_ident) { struct stat statbuf; struct strbuf committer_ident = STRBUF_INIT; int commitable, saved_color_setting; struct strbuf sb = STRBUF_INIT; char *buffer; const char *hook_arg1 = NULL; const char *hook_arg2 = NULL; int ident_shown = 0; int clean_message_contents = (cleanup_mode != CLEANUP_NONE); if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; if (squash_message) { /* * Insert the proper subject line before other commit * message options add their content. */ if (use_message && !strcmp(use_message, squash_message)) strbuf_addstr(&sb, "squash! "); else { struct pretty_print_context ctx = {0}; struct commit *c; c = lookup_commit_reference_by_name(squash_message); if (!c) die(_("could not lookup commit %s"), squash_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(c, "squash! %s\n\n", &sb, &ctx); } } if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; } else if (logfile && !strcmp(logfile, "-")) { if (isatty(0)) fprintf(stderr, _("(reading log message from standard input)\n")); if (strbuf_read(&sb, 0, 0) < 0) die_errno(_("could not read log from standard input")); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) die_errno(_("could not read log file '%s'"), logfile); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); if (!buffer || buffer[2] == '\0') die(_("commit has empty message")); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; hook_arg2 = use_message; } else if (fixup_message) { struct pretty_print_context ctx = {0}; struct commit *commit; commit = lookup_commit_reference_by_name(fixup_message); if (!commit) die(_("could not lookup commit %s"), fixup_message); ctx.output_encoding = get_commit_output_encoding(); format_commit_message(commit, "fixup! %s\n\n", &sb, &ctx); hook_arg1 = "message"; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) die_errno(_("could not read MERGE_MSG")); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) die_errno(_("could not read SQUASH_MSG")); hook_arg1 = "squash"; } else if (template_file) { if (strbuf_read_file(&sb, template_file, 0) < 0) die_errno(_("could not read '%s'"), template_file); hook_arg1 = "template"; clean_message_contents = 0; } /* * The remaining cases don't modify the template message, but * just set the argument(s) to the prepare-commit-msg hook. */ else if (whence == FROM_MERGE) hook_arg1 = "merge"; else if (whence == FROM_CHERRY_PICK) { hook_arg1 = "commit"; hook_arg2 = "CHERRY_PICK_HEAD"; } if (squash_message) { /* * If squash_commit was used for the commit subject, * then we're possibly hijacking other commit log options. * Reset the hook args to tell the real story. */ hook_arg1 = "message"; hook_arg2 = ""; } s->fp = fopen(git_path(commit_editmsg), "w"); if (s->fp == NULL) die_errno(_("could not open '%s'"), git_path(commit_editmsg)); if (clean_message_contents) stripspace(&sb, 0); if (signoff) { struct strbuf sob = STRBUF_INIT; int i; strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); strbuf_addch(&sob, '\n'); for (i = sb.len - 1; i > 0 && sb.buf[i - 1] != '\n'; i--) ; /* do nothing */ if (prefixcmp(sb.buf + i, sob.buf)) { if (!i || !ends_rfc2822_footer(&sb)) strbuf_addch(&sb, '\n'); strbuf_addbuf(&sb, &sob); } strbuf_release(&sob); } if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len) die_errno(_("could not write commit template")); strbuf_release(&sb); /* This checks and barfs if author is badly specified */ determine_author_info(author_ident); /* This checks if committer ident is explicitly given */ strbuf_addstr(&committer_ident, git_committer_info(0)); if (use_editor && include_status) { char *ai_tmp, *ci_tmp; if (whence != FROM_COMMIT) status_printf_ln(s, GIT_COLOR_NORMAL, _("\n" "It looks like you may be committing a %s.\n" "If this is not correct, please remove the file\n" " %s\n" "and try again.\n" ""), whence_s(), git_path(whence == FROM_MERGE ? "MERGE_HEAD" : "CHERRY_PICK_HEAD")); fprintf(s->fp, "\n"); status_printf(s, GIT_COLOR_NORMAL, _("Please enter the commit message for your changes.")); if (cleanup_mode == CLEANUP_ALL) status_printf_more(s, GIT_COLOR_NORMAL, _(" Lines starting\n" "with '#' will be ignored, and an empty" " message aborts the commit.\n")); else /* CLEANUP_SPACE, that is. */ status_printf_more(s, GIT_COLOR_NORMAL, _(" Lines starting\n" "with '#' will be kept; you may remove them" " yourself if you want to.\n" "An empty message aborts the commit.\n")); if (only_include_assumed) status_printf_ln(s, GIT_COLOR_NORMAL, "%s", only_include_assumed); ai_tmp = cut_ident_timestamp_part(author_ident->buf); ci_tmp = cut_ident_timestamp_part(committer_ident.buf); if (strcmp(author_ident->buf, committer_ident.buf)) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Author: %s"), ident_shown++ ? "" : "\n", author_ident->buf); if (!user_ident_sufficiently_given()) status_printf_ln(s, GIT_COLOR_NORMAL, _("%s" "Committer: %s"), ident_shown++ ? "" : "\n", committer_ident.buf); if (ident_shown) status_printf_ln(s, GIT_COLOR_NORMAL, ""); saved_color_setting = s->use_color; s->use_color = 0; commitable = run_status(s->fp, index_file, prefix, 1, s); s->use_color = saved_color_setting; *ai_tmp = ' '; *ci_tmp = ' '; } else { unsigned char sha1[20]; const char *parent = "HEAD"; if (!active_nr && read_cache() < 0) die(_("Cannot read index")); if (amend) parent = "HEAD^1"; if (get_sha1(parent, sha1)) commitable = !!active_nr; else commitable = index_differs_from(parent, 0); } strbuf_release(&committer_ident); fclose(s->fp); /* * Reject an attempt to record a non-merge empty commit without * explicit --allow-empty. In the cherry-pick case, it may be * empty due to conflict resolution, which the user should okay. */ if (!commitable && whence != FROM_MERGE && !allow_empty && !(amend && is_a_merge(head_sha1))) { run_status(stdout, index_file, prefix, 0, s); if (amend) fputs(_(empty_amend_advice), stderr); else if (whence == FROM_CHERRY_PICK) fputs(_(empty_cherry_pick_advice), stderr); return 0; } /* * Re-read the index as pre-commit hook could have updated it, * and write it out as a tree. We must do this before we invoke * the editor and after we invoke run_status above. */ discard_cache(); read_cache_from(index_file); if (!active_cache_tree) active_cache_tree = cache_tree(); if (cache_tree_update(active_cache_tree, active_cache, active_nr, 0, 0) < 0) { error(_("Error building trees")); return 0; } if (run_hook(index_file, "prepare-commit-msg", git_path(commit_editmsg), hook_arg1, hook_arg2, NULL)) return 0; if (use_editor) { char index[PATH_MAX]; const char *env[2] = { NULL }; env[0] = index; snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file); if (launch_editor(git_path(commit_editmsg), NULL, env)) { fprintf(stderr, _("Please supply the message using either -m or -F option.\n")); exit(1); } } if (!no_verify && run_hook(index_file, "commit-msg", git_path(commit_editmsg), NULL)) { return 0; } return 1; }