int dwim_log(const char *str, int len, unsigned char *sha1, char **log) { char *last_branch = substitute_branch_name(&str, &len); const char **p; int logs_found = 0; struct strbuf path = STRBUF_INIT; *log = NULL; for (p = ref_rev_parse_rules; *p; p++) { unsigned char hash[20]; const char *ref, *it; strbuf_reset(&path); strbuf_addf(&path, *p, len, str); ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING, hash, NULL); if (!ref) continue; if (reflog_exists(path.buf)) it = path.buf; else if (strcmp(ref, path.buf) && reflog_exists(ref)) it = ref; else continue; if (!logs_found++) { *log = xstrdup(it); hashcpy(sha1, hash); } if (!warn_ambiguous_refs) break; } strbuf_release(&path); free(last_branch); return logs_found; }
int dwim_log(const char *str, int len, unsigned char *sha1, char **log) { char *last_branch = substitute_branch_name(&str, &len); const char **p; int logs_found = 0; *log = NULL; for (p = ref_rev_parse_rules; *p; p++) { unsigned char hash[20]; char path[PATH_MAX]; const char *ref, *it; mksnpath(path, sizeof(path), *p, len, str); ref = resolve_ref_unsafe(path, RESOLVE_REF_READING, hash, NULL); if (!ref) continue; if (reflog_exists(path)) it = path; else if (strcmp(ref, path) && reflog_exists(ref)) it = ref; else continue; if (!logs_found++) { *log = xstrdup(it); hashcpy(sha1, hash); } if (!warn_ambiguous_refs) break; } free(last_branch); return logs_found; }
static int fsck_head_link(void) { int null_is_error = 0; if (verbose) fprintf(stderr, "Checking HEAD link\n"); head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL); if (!head_points_at) { errors_found |= ERROR_REFS; return error("Invalid HEAD"); } if (!strcmp(head_points_at, "HEAD")) /* detached HEAD */ null_is_error = 1; else if (!starts_with(head_points_at, "refs/heads/")) { errors_found |= ERROR_REFS; return error("HEAD points to something strange (%s)", head_points_at); } if (is_null_oid(&head_oid)) { if (null_is_error) { errors_found |= ERROR_REFS; return error("HEAD: detached HEAD points at nothing"); } fprintf(stderr, "notice: HEAD points to an unborn branch (%s)\n", head_points_at + 11); } return 0; }
static char *get_default_remote(void) { char *dest = NULL, *ret; unsigned char sha1[20]; struct strbuf sb = STRBUF_INIT; const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL); if (!refname) die(_("No such ref: %s"), "HEAD"); /* detached HEAD */ if (!strcmp(refname, "HEAD")) return xstrdup("origin"); if (!skip_prefix(refname, "refs/heads/", &refname)) die(_("Expecting a full ref name, got %s"), refname); strbuf_addf(&sb, "branch.%s.remote", refname); if (git_config_get_string(sb.buf, &dest)) ret = xstrdup("origin"); else ret = dest; strbuf_release(&sb); return ret; }
int expand_ref(const char *str, int len, unsigned char *sha1, char **ref) { const char **p, *r; int refs_found = 0; struct strbuf fullref = STRBUF_INIT; *ref = NULL; for (p = ref_rev_parse_rules; *p; p++) { unsigned char sha1_from_ref[20]; unsigned char *this_result; int flag; this_result = refs_found ? sha1_from_ref : sha1; strbuf_reset(&fullref); strbuf_addf(&fullref, *p, len, str); r = resolve_ref_unsafe(fullref.buf, RESOLVE_REF_READING, this_result, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); if (!warn_ambiguous_refs) break; } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) { warning("ignoring dangling symref %s.", fullref.buf); } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) { warning("ignoring broken ref %s.", fullref.buf); } } strbuf_release(&fullref); return refs_found; }
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); }
static const char *remote_submodule_branch(const char *path) { const struct submodule *sub; gitmodules_config(); git_config(submodule_config, NULL); sub = submodule_from_path(null_sha1, path); if (!sub) return NULL; if (!sub->branch) return "master"; if (!strcmp(sub->branch, ".")) { unsigned char sha1[20]; const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL); if (!refname) die(_("No such ref: %s"), "HEAD"); /* detached HEAD */ if (!strcmp(refname, "HEAD")) die(_("Submodule (%s) branch configured to inherit " "branch from superproject, but the superproject " "is not on any branch"), sub->name); if (!skip_prefix(refname, "refs/heads/", &refname)) die(_("Expecting a full ref name, got %s"), refname); return refname; } return sub->branch; }
static char *find_branch_name(struct rev_info *rev) { int i, positive = -1; unsigned char branch_sha1[20]; struct strbuf buf = STRBUF_INIT; const char *branch; for (i = 0; i < rev->cmdline.nr; i++) { if (rev->cmdline.rev[i].flags & UNINTERESTING) continue; if (positive < 0) positive = i; else return NULL; } if (positive < 0) return NULL; strbuf_addf(&buf, "refs/heads/%s", rev->cmdline.rev[positive].name); branch = resolve_ref_unsafe(buf.buf, branch_sha1, 1, NULL); if (!branch || prefixcmp(branch, "refs/heads/") || hashcmp(rev->cmdline.rev[positive].item->sha1, branch_sha1)) branch = NULL; strbuf_release(&buf); if (branch) return xstrdup(rev->cmdline.rev[positive].name); return NULL; }
/* * Do we have HEAD in the output, and also the branch it points at? * If so, find that decoration entry for that current branch. */ static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration) { const struct name_decoration *list, *head = NULL; const char *branch_name = NULL; unsigned char unused[20]; int rru_flags; /* First find HEAD */ for (list = decoration; list; list = list->next) if (list->type == DECORATION_REF_HEAD) { head = list; break; } if (!head) return NULL; /* Now resolve and find the matching current branch */ branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags); if (!(rru_flags & REF_ISSYMREF)) return NULL; if (!starts_with(branch_name, "refs/")) return NULL; /* OK, do we have that ref in the list? */ for (list = decoration; list; list = list->next) if ((list->type == DECORATION_REF_LOCAL) && !strcmp(branch_name, list->name)) { return list; } return NULL; }
int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref) { char *last_branch = substitute_branch_name(&str, &len); const char **p, *r; int refs_found = 0; *ref = NULL; for (p = ref_rev_parse_rules; *p; p++) { char fullref[PATH_MAX]; unsigned char sha1_from_ref[20]; unsigned char *this_result; int flag; this_result = refs_found ? sha1_from_ref : sha1; mksnpath(fullref, sizeof(fullref), *p, len, str); r = resolve_ref_unsafe(fullref, RESOLVE_REF_READING, this_result, &flag); if (r) { if (!refs_found++) *ref = xstrdup(r); if (!warn_ambiguous_refs) break; } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD")) { warning("ignoring dangling symref %s.", fullref); } else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) { warning("ignoring broken ref %s.", fullref); } } free(last_branch); return refs_found; }
static char *guess_defbranch(void) { const char *ref; unsigned char sha1[20]; ref = resolve_ref_unsafe("HEAD", sha1, 0, NULL); if (!ref || prefixcmp(ref, "refs/heads/")) return "master"; return xstrdup(ref + 11); }
/** * Add the head_sha1 and head_ref (if not detached) to the given worktree */ static void add_head_info(struct strbuf *head_ref, struct worktree *worktree) { if (head_ref->len) { if (worktree->is_detached) { get_sha1_hex(head_ref->buf, worktree->head_sha1); } else { resolve_ref_unsafe(head_ref->buf, 0, worktree->head_sha1, NULL); worktree->head_ref = strbuf_detach(head_ref, NULL); } } }
static void check_aliased_update(struct command *cmd, struct string_list *list) { struct strbuf buf = STRBUF_INIT; const char *dst_name; struct string_list_item *item; struct command *dst_cmd; unsigned char sha1[GIT_SHA1_RAWSZ]; char cmd_oldh[GIT_SHA1_HEXSZ + 1], cmd_newh[GIT_SHA1_HEXSZ + 1], dst_oldh[GIT_SHA1_HEXSZ + 1], dst_newh[GIT_SHA1_HEXSZ + 1]; int flag; strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); dst_name = resolve_ref_unsafe(buf.buf, 0, sha1, &flag); strbuf_release(&buf); if (!(flag & REF_ISSYMREF)) return; if (!dst_name) { rp_error("refusing update to broken symref '%s'", cmd->ref_name); cmd->skip_update = 1; cmd->error_string = "broken symref"; return; } dst_name = strip_namespace(dst_name); if ((item = string_list_lookup(list, dst_name)) == NULL) return; cmd->skip_update = 1; dst_cmd = (struct command *) item->util; if (!hashcmp(cmd->old_sha1, dst_cmd->old_sha1) && !hashcmp(cmd->new_sha1, dst_cmd->new_sha1)) return; dst_cmd->skip_update = 1; find_unique_abbrev_r(cmd_oldh, cmd->old_sha1, DEFAULT_ABBREV); find_unique_abbrev_r(cmd_newh, cmd->new_sha1, DEFAULT_ABBREV); find_unique_abbrev_r(dst_oldh, dst_cmd->old_sha1, DEFAULT_ABBREV); find_unique_abbrev_r(dst_newh, dst_cmd->new_sha1, DEFAULT_ABBREV); rp_error("refusing inconsistent update between symref '%s' (%s..%s) and" " its target '%s' (%s..%s)", cmd->ref_name, cmd_oldh, cmd_newh, dst_cmd->ref_name, dst_oldh, dst_newh); cmd->error_string = dst_cmd->error_string = "inconsistent aliased update"; }
static char *resolve_symref(const char *src, const char *prefix) { unsigned char sha1[20]; int flag; const char *dst; dst = resolve_ref_unsafe(src, sha1, 0, &flag); if (!(dst && (flag & REF_ISSYMREF))) return NULL; if (prefix) skip_prefix(dst, prefix, &dst); return xstrdup(dst); }
static int find_symref(const char *refname, const struct object_id *oid, int flag, void *cb_data) { const char *symref_target; struct string_list_item *item; if ((flag & REF_ISSYMREF) == 0) return 0; symref_target = resolve_ref_unsafe(refname, 0, NULL, &flag); if (!symref_target || (flag & REF_ISSYMREF) == 0) die("'%s' is a symref but it is not?", refname); item = string_list_append(cb_data, refname); item->util = xstrdup(symref_target); return 0; }
static void check_symref(const char *HEAD, int quiet) { unsigned char sha1[20]; int flag; const char *refs_heads_master = resolve_ref_unsafe(HEAD, sha1, 0, &flag); if (!refs_heads_master) die("No such ref: %s", HEAD); else if (!(flag & REF_ISSYMREF)) { if (!quiet) die("ref %s is not a symbolic ref", HEAD); else exit(1); } puts(refs_heads_master); }
static void set_upstreams(struct transport *transport, struct ref *refs, int pretend) { struct ref *ref; for (ref = refs; ref; ref = ref->next) { const char *localname; const char *tmp; const char *remotename; unsigned char sha[20]; int flag = 0; /* * Check suitability for tracking. Must be successful / * already up-to-date ref create/modify (not delete). */ if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) continue; if (!ref->peer_ref) continue; if (is_null_oid(&ref->new_oid)) continue; /* Follow symbolic refs (mainly for HEAD). */ localname = ref->peer_ref->name; remotename = ref->name; tmp = resolve_ref_unsafe(localname, RESOLVE_REF_READING, sha, &flag); if (tmp && flag & REF_ISSYMREF && starts_with(tmp, "refs/heads/")) localname = tmp; /* Both source and destination must be local branches. */ if (!localname || !starts_with(localname, "refs/heads/")) continue; if (!remotename || !starts_with(remotename, "refs/heads/")) continue; if (!pretend) install_branch_config(BRANCH_CONFIG_VERBOSE, localname + 11, transport->remote->name, remotename); else printf(_("Would set upstream of '%s' to '%s' of '%s'\n"), localname + 11, remotename + 11, transport->remote->name); } }
static int show_head_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct strbuf *buf = cb_data; if (flag & REF_ISSYMREF) { unsigned char unused[20]; const char *target = resolve_ref_unsafe(refname, unused, 1, NULL); const char *target_nons = strip_namespace(target); strbuf_addf(buf, "ref: %s\n", target_nons); } else { strbuf_addf(buf, "%s\n", sha1_to_hex(sha1)); } return 0; }
static int show_head_ref(const char *refname, const struct object_id *oid, int flag, void *cb_data) { struct strbuf *buf = cb_data; if (flag & REF_ISSYMREF) { const char *target = resolve_ref_unsafe(refname, RESOLVE_REF_READING, NULL, NULL); if (target) strbuf_addf(buf, "ref: %s\n", strip_namespace(target)); } else { strbuf_addf(buf, "%s\n", oid_to_hex(oid)); } return 0; }
static void check_symref(const char *HEAD, int quiet) { unsigned char sha1[20]; int flag; const char *refname = resolve_ref_unsafe(HEAD, sha1, 0, &flag); if (!refname) die("No such ref: %s", HEAD); else if (!(flag & REF_ISSYMREF)) { if (!quiet) die("ref %s is not a symbolic ref", HEAD); else exit(1); } if (shorten) refname = shorten_unambiguous_ref(refname, 0); puts(refname); }
int validate_new_branchname(const char *name, struct strbuf *ref, int force, int attr_only) { if (strbuf_check_branch_ref(ref, name)) die(_("'%s' is not a valid branch name."), name); if (!ref_exists(ref->buf)) return 0; else if (!force && !attr_only) die(_("A branch named '%s' already exists."), ref->buf + strlen("refs/heads/")); if (!attr_only) { const char *head; unsigned char sha1[20]; head = resolve_ref_unsafe("HEAD", sha1, 0, NULL); if (!is_bare_repository() && head && !strcmp(head, ref->buf)) die(_("Cannot force update the current branch.")); } return 1; }
static int warn_if_dangling_symref(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct warn_if_dangling_data *d = cb_data; const char *resolves_to; struct object_id junk; if (!(flags & REF_ISSYMREF)) return 0; resolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL); if (!resolves_to || (d->refname ? strcmp(resolves_to, d->refname) : !string_list_has_string(d->refnames, resolves_to))) { return 0; } fprintf(d->fp, d->msg_fmt, refname); fputc('\n', d->fp); return 0; }
static struct commit *dwim_reverse_initial(struct rev_info *revs, const char **name_p) { /* * DWIM "git blame --reverse ONE -- PATH" as * "git blame --reverse ONE..HEAD -- PATH" but only do so * when it makes sense. */ struct object *obj; struct commit *head_commit; struct object_id head_oid; if (revs->pending.nr != 1) return NULL; /* Is that sole rev a committish? */ obj = revs->pending.objects[0].item; obj = deref_tag(obj, NULL, 0); if (obj->type != OBJ_COMMIT) return NULL; /* Do we have HEAD? */ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL)) return NULL; head_commit = lookup_commit_reference_gently(&head_oid, 1); if (!head_commit) return NULL; /* Turn "ONE" into "ONE..HEAD" then */ obj->flags |= UNINTERESTING; add_pending_object(revs, &head_commit->object, "HEAD"); if (name_p) *name_p = revs->pending.objects[0].name; return (struct commit *)obj; }
static void print_summary(const char *prefix, const unsigned char *sha1, int initial_commit) { struct rev_info rev; struct commit *commit; struct strbuf format = STRBUF_INIT; unsigned char junk_sha1[20]; const char *head; struct pretty_print_context pctx = {0}; struct strbuf author_ident = STRBUF_INIT; struct strbuf committer_ident = STRBUF_INIT; commit = lookup_commit(sha1); if (!commit) die(_("couldn't look up newly created commit")); if (parse_commit(commit)) die(_("could not parse newly created commit")); strbuf_addstr(&format, "format:%h] %s"); format_commit_message(commit, "%an <%ae>", &author_ident, &pctx); format_commit_message(commit, "%cn <%ce>", &committer_ident, &pctx); if (strbuf_cmp(&author_ident, &committer_ident)) { strbuf_addstr(&format, "\n Author: "); strbuf_addbuf_percentquote(&format, &author_ident); } if (!committer_ident_sufficiently_given()) { strbuf_addstr(&format, "\n Committer: "); strbuf_addbuf_percentquote(&format, &committer_ident); if (advice_implicit_identity) { strbuf_addch(&format, '\n'); strbuf_addstr(&format, _(implicit_ident_advice)); } } strbuf_release(&author_ident); strbuf_release(&committer_ident); init_revisions(&rev, prefix); setup_revisions(0, NULL, &rev, NULL); rev.diff = 1; rev.diffopt.output_format = DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY; rev.verbose_header = 1; rev.show_root_diff = 1; get_commit_format(format.buf, &rev); rev.always_show_header = 0; rev.diffopt.detect_rename = 1; rev.diffopt.break_opt = 0; diff_setup_done(&rev.diffopt); head = resolve_ref_unsafe("HEAD", junk_sha1, 0, NULL); printf("[%s%s ", starts_with(head, "refs/heads/") ? head + 11 : !strcmp(head, "HEAD") ? _("detached HEAD") : head, initial_commit ? _(" (root-commit)") : ""); if (!log_tree_commit(&rev, commit)) { rev.always_show_header = 1; rev.use_terminator = 1; log_tree_commit(&rev, commit); } strbuf_release(&format); }
int cmd_format_patch(int argc, const char **argv, const char *prefix) { struct commit *commit; struct commit **list = NULL; struct rev_info rev; struct setup_revision_opt s_r_opt; int nr = 0, total, i; int use_stdout = 0; int start_number = -1; int numbered_files = 0; /* _just_ numbers */ int ignore_if_in_upstream = 0; int cover_letter = 0; int boundary_count = 0; int no_binary_diff = 0; struct commit *origin = NULL, *head = NULL; const char *in_reply_to = NULL; struct patch_ids ids; char *add_signoff = NULL; struct strbuf buf = STRBUF_INIT; int use_patch_format = 0; int quiet = 0; char *branch_name = NULL; const struct option builtin_format_patch_options[] = { { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL, N_("use [PATCH n/m] even with a single patch"), PARSE_OPT_NOARG, numbered_callback }, { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL, N_("use [PATCH] even with multiple patches"), PARSE_OPT_NOARG, no_numbered_callback }, OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")), OPT_BOOLEAN(0, "stdout", &use_stdout, N_("print patches to standard out")), OPT_BOOLEAN(0, "cover-letter", &cover_letter, N_("generate a cover letter")), OPT_BOOLEAN(0, "numbered-files", &numbered_files, N_("use simple number sequence for output file names")), OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"), N_("use <sfx> instead of '.patch'")), OPT_INTEGER(0, "start-number", &start_number, N_("start numbering patches at <n> instead of 1")), { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"), N_("Use [<prefix>] instead of [PATCH]"), PARSE_OPT_NONEG, subject_prefix_callback }, { OPTION_CALLBACK, 'o', "output-directory", &output_directory, N_("dir"), N_("store resulting files in <dir>"), PARSE_OPT_NONEG, output_directory_callback }, { OPTION_CALLBACK, 'k', "keep-subject", &rev, NULL, N_("don't strip/add [PATCH]"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback }, OPT_BOOLEAN(0, "no-binary", &no_binary_diff, N_("don't output binary diffs")), OPT_BOOLEAN(0, "ignore-if-in-upstream", &ignore_if_in_upstream, N_("don't include a patch matching a commit upstream")), { OPTION_BOOLEAN, 'p', "no-stat", &use_patch_format, NULL, N_("show patch format instead of default (patch + stat)"), PARSE_OPT_NONEG | PARSE_OPT_NOARG }, OPT_GROUP(N_("Messaging")), { OPTION_CALLBACK, 0, "add-header", NULL, N_("header"), N_("add email header"), 0, header_callback }, { OPTION_CALLBACK, 0, "to", NULL, N_("email"), N_("add To: header"), 0, to_callback }, { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"), 0, cc_callback }, OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"), N_("make first mail a reply to <message-id>")), { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"), N_("attach the patch"), PARSE_OPT_OPTARG, attach_callback }, { OPTION_CALLBACK, 0, "inline", &rev, N_("boundary"), N_("inline the patch"), PARSE_OPT_OPTARG | PARSE_OPT_NONEG, inline_callback }, { OPTION_CALLBACK, 0, "thread", &thread, N_("style"), N_("enable message threading, styles: shallow, deep"), PARSE_OPT_OPTARG, thread_callback }, OPT_STRING(0, "signature", &signature, N_("signature"), N_("add a signature")), OPT_BOOLEAN(0, "quiet", &quiet, N_("don't print the patch filenames")), OPT_END() }; extra_hdr.strdup_strings = 1; extra_to.strdup_strings = 1; extra_cc.strdup_strings = 1; git_config(git_format_config, NULL); init_revisions(&rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; rev.verbose_header = 1; rev.diff = 1; rev.max_parents = 1; DIFF_OPT_SET(&rev.diffopt, RECURSIVE); rev.subject_prefix = fmt_patch_subject_prefix; memset(&s_r_opt, 0, sizeof(s_r_opt)); s_r_opt.def = "HEAD"; s_r_opt.revarg_opt = REVARG_COMMITTISH; if (default_attach) { rev.mime_boundary = default_attach; rev.no_inline = 1; } /* * Parse the arguments before setup_revisions(), or something * like "git format-patch -o a123 HEAD^.." may fail; a123 is * possibly a valid SHA1. */ argc = parse_options(argc, argv, prefix, builtin_format_patch_options, builtin_format_patch_usage, PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH); if (do_signoff) { const char *committer; const char *endpos; committer = git_committer_info(IDENT_STRICT); endpos = strchr(committer, '>'); if (!endpos) die(_("bogus committer info %s"), committer); add_signoff = xmemdupz(committer, endpos - committer + 1); } for (i = 0; i < extra_hdr.nr; i++) { strbuf_addstr(&buf, extra_hdr.items[i].string); strbuf_addch(&buf, '\n'); } if (extra_to.nr) strbuf_addstr(&buf, "To: "); for (i = 0; i < extra_to.nr; i++) { if (i) strbuf_addstr(&buf, " "); strbuf_addstr(&buf, extra_to.items[i].string); if (i + 1 < extra_to.nr) strbuf_addch(&buf, ','); strbuf_addch(&buf, '\n'); } if (extra_cc.nr) strbuf_addstr(&buf, "Cc: "); for (i = 0; i < extra_cc.nr; i++) { if (i) strbuf_addstr(&buf, " "); strbuf_addstr(&buf, extra_cc.items[i].string); if (i + 1 < extra_cc.nr) strbuf_addch(&buf, ','); strbuf_addch(&buf, '\n'); } rev.extra_headers = strbuf_detach(&buf, NULL); if (start_number < 0) start_number = 1; /* * If numbered is set solely due to format.numbered in config, * and it would conflict with --keep-subject (-k) from the * command line, reset "numbered". */ if (numbered && keep_subject && !numbered_cmdline_opt) numbered = 0; if (numbered && keep_subject) die (_("-n and -k are mutually exclusive.")); if (keep_subject && subject_prefix) die (_("--subject-prefix and -k are mutually exclusive.")); rev.preserve_subject = keep_subject; argc = setup_revisions(argc, argv, &rev, &s_r_opt); if (argc > 1) die (_("unrecognized argument: %s"), argv[1]); if (rev.diffopt.output_format & DIFF_FORMAT_NAME) die(_("--name-only does not make sense")); if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS) die(_("--name-status does not make sense")); if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF) die(_("--check does not make sense")); if (!use_patch_format && (!rev.diffopt.output_format || rev.diffopt.output_format == DIFF_FORMAT_PATCH)) rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY; /* Always generate a patch */ rev.diffopt.output_format |= DIFF_FORMAT_PATCH; if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff) DIFF_OPT_SET(&rev.diffopt, BINARY); if (rev.show_notes) init_display_notes(&rev.notes_opt); if (!use_stdout) output_directory = set_outdir(prefix, output_directory); else setup_pager(); if (output_directory) { if (use_stdout) die(_("standard output, or directory, which one?")); if (mkdir(output_directory, 0777) < 0 && errno != EEXIST) die_errno(_("Could not create directory '%s'"), output_directory); } if (rev.pending.nr == 1) { if (rev.max_count < 0 && !rev.show_root_diff) { /* * This is traditional behaviour of "git format-patch * origin" that prepares what the origin side still * does not have. */ unsigned char sha1[20]; const char *ref; rev.pending.objects[0].item->flags |= UNINTERESTING; add_head_to_pending(&rev); ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL); if (ref && !prefixcmp(ref, "refs/heads/")) branch_name = xstrdup(ref + strlen("refs/heads/")); else branch_name = xstrdup(""); /* no branch */ } /* * Otherwise, it is "format-patch -22 HEAD", and/or * "format-patch --root HEAD". The user wants * get_revision() to do the usual traversal. */ } /* * We cannot move this anywhere earlier because we do want to * know if --root was given explicitly from the command line. */ rev.show_root_diff = 1; if (cover_letter) { /* * NEEDSWORK:randomly pick one positive commit to show * diffstat; this is often the tip and the command * happens to do the right thing in most cases, but a * complex command like "--cover-letter a b c ^bottom" * picks "c" and shows diffstat between bottom..c * which may not match what the series represents at * all and totally broken. */ int i; for (i = 0; i < rev.pending.nr; i++) { struct object *o = rev.pending.objects[i].item; if (!(o->flags & UNINTERESTING)) head = (struct commit *)o; } /* There is nothing to show; it is not an error, though. */ if (!head) return 0; if (!branch_name) branch_name = find_branch_name(&rev); } if (ignore_if_in_upstream) { /* Don't say anything if head and upstream are the same. */ if (rev.pending.nr == 2) { struct object_array_entry *o = rev.pending.objects; if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0) return 0; } get_patch_ids(&rev, &ids); } if (!use_stdout) realstdout = xfdopen(xdup(1), "w"); if (prepare_revision_walk(&rev)) die(_("revision walk setup failed")); rev.boundary = 1; while ((commit = get_revision(&rev)) != NULL) { if (commit->object.flags & BOUNDARY) { boundary_count++; origin = (boundary_count == 1) ? commit : NULL; continue; } if (ignore_if_in_upstream && has_commit_patch_id(commit, &ids)) continue; nr++; list = xrealloc(list, nr * sizeof(list[0])); list[nr - 1] = commit; } total = nr; if (!keep_subject && auto_number && total > 1) numbered = 1; if (numbered) rev.total = total + start_number - 1; if (in_reply_to || thread || cover_letter) rev.ref_message_ids = xcalloc(1, sizeof(struct string_list)); if (in_reply_to) { const char *msgid = clean_message_id(in_reply_to); string_list_append(rev.ref_message_ids, msgid); } rev.numbered_files = numbered_files; rev.patch_suffix = fmt_patch_suffix; if (cover_letter) { if (thread) gen_message_id(&rev, "cover"); make_cover_letter(&rev, use_stdout, numbered, numbered_files, origin, nr, list, head, branch_name, quiet); total++; start_number--; } rev.add_signoff = add_signoff; while (0 <= --nr) { int shown; commit = list[nr]; rev.nr = total - nr + (start_number - 1); /* Make the second and subsequent mails replies to the first */ if (thread) { /* Have we already had a message ID? */ if (rev.message_id) { /* * For deep threading: make every mail * a reply to the previous one, no * matter what other options are set. * * For shallow threading: * * Without --cover-letter and * --in-reply-to, make every mail a * reply to the one before. * * With --in-reply-to but no * --cover-letter, make every mail a * reply to the <reply-to>. * * With --cover-letter, make every * mail but the cover letter a reply * to the cover letter. The cover * letter is a reply to the * --in-reply-to, if specified. */ if (thread == THREAD_SHALLOW && rev.ref_message_ids->nr > 0 && (!cover_letter || rev.nr > 1)) free(rev.message_id); else string_list_append(rev.ref_message_ids, rev.message_id); } gen_message_id(&rev, sha1_to_hex(commit->object.sha1)); } if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); free(commit->buffer); commit->buffer = NULL; /* We put one extra blank line between formatted * patches and this flag is used by log-tree code * to see if it needs to emit a LF before showing * the log; when using one file per patch, we do * not want the extra blank line. */ if (!use_stdout) rev.shown_one = 0; if (shown) { if (rev.mime_boundary) printf("\n--%s%s--\n\n\n", mime_boundary_leader, rev.mime_boundary); else print_signature(); } if (!use_stdout) fclose(stdout); } free(list); free(branch_name); string_list_clear(&extra_to, 0); string_list_clear(&extra_cc, 0); string_list_clear(&extra_hdr, 0); if (ignore_if_in_upstream) free_patch_ids(&ids); return 0; }
static int delete_branches(int argc, const char **argv, int force, int kinds, int quiet) { struct commit *head_rev = NULL; unsigned char sha1[20]; char *name = NULL; const char *fmt; int i; int ret = 0; int remote_branch = 0; struct strbuf bname = STRBUF_INIT; switch (kinds) { case REF_REMOTE_BRANCH: fmt = "refs/remotes/%s"; /* For subsequent UI messages */ remote_branch = 1; force = 1; break; case REF_LOCAL_BRANCH: fmt = "refs/heads/%s"; break; default: die(_("cannot use -a with -d")); } if (!force) { head_rev = lookup_commit_reference(head_sha1); if (!head_rev) die(_("Couldn't look up commit object for HEAD")); } for (i = 0; i < argc; i++, strbuf_release(&bname)) { const char *target; int flags = 0; strbuf_branchname(&bname, argv[i]); if (kinds == REF_LOCAL_BRANCH && !strcmp(head, bname.buf)) { error(_("Cannot delete the branch '%s' " "which you are currently on."), bname.buf); ret = 1; continue; } free(name); name = mkpathdup(fmt, bname.buf); target = resolve_ref_unsafe(name, sha1, 0, &flags); if (!target || (!(flags & REF_ISSYMREF) && is_null_sha1(sha1))) { error(remote_branch ? _("remote branch '%s' not found.") : _("branch '%s' not found."), bname.buf); ret = 1; continue; } if (!(flags & REF_ISSYMREF) && check_branch_commit(bname.buf, name, sha1, head_rev, kinds, force)) { ret = 1; continue; } if (delete_ref(name, sha1, REF_NODEREF)) { error(remote_branch ? _("Error deleting remote branch '%s'") : _("Error deleting branch '%s'"), bname.buf); ret = 1; continue; } if (!quiet) { printf(remote_branch ? _("Deleted remote branch %s (was %s).\n") : _("Deleted branch %s (was %s).\n"), bname.buf, (flags & REF_ISSYMREF) ? target : find_unique_abbrev(sha1, DEFAULT_ABBREV)); } delete_branch_config(bname.buf); } free(name); return(ret); }
int ref_exists(const char *refname) { unsigned char sha1[20]; return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL); }
int read_ref_full(const char *refname, int resolve_flags, unsigned char *sha1, int *flags) { if (resolve_ref_unsafe(refname, resolve_flags, sha1, flags)) return 0; return -1; }
char *resolve_refdup(const char *refname, int resolve_flags, unsigned char *sha1, int *flags) { return xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags, sha1, flags)); }
static int do_create_stash(struct pathspec ps, struct strbuf *stash_msg_buf, int include_untracked, int patch_mode, struct stash_info *info, struct strbuf *patch, int quiet) { int ret = 0; int flags = 0; int untracked_commit_option = 0; const char *head_short_sha1 = NULL; const char *branch_ref = NULL; const char *branch_name = "(no branch)"; struct commit *head_commit = NULL; struct commit_list *parents = NULL; struct strbuf msg = STRBUF_INIT; struct strbuf commit_tree_label = STRBUF_INIT; struct strbuf untracked_files = STRBUF_INIT; prepare_fallback_ident("git stash", "git@stash"); read_cache_preload(NULL); refresh_cache(REFRESH_QUIET); if (get_oid("HEAD", &info->b_commit)) { if (!quiet) fprintf_ln(stderr, _("You do not have " "the initial commit yet")); ret = -1; goto done; } else { head_commit = lookup_commit(the_repository, &info->b_commit); } if (!check_changes(ps, include_untracked, &untracked_files)) { ret = 1; goto done; } branch_ref = resolve_ref_unsafe("HEAD", 0, NULL, &flags); if (flags & REF_ISSYMREF) branch_name = strrchr(branch_ref, '/') + 1; head_short_sha1 = find_unique_abbrev(&head_commit->object.oid, DEFAULT_ABBREV); strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1); pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg); strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf); commit_list_insert(head_commit, &parents); if (write_cache_as_tree(&info->i_tree, 0, NULL) || commit_tree(commit_tree_label.buf, commit_tree_label.len, &info->i_tree, parents, &info->i_commit, NULL, NULL)) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " "index state")); ret = -1; goto done; } if (include_untracked) { if (save_untracked_files(info, &msg, untracked_files)) { if (!quiet) fprintf_ln(stderr, _("Cannot save " "the untracked files")); ret = -1; goto done; } untracked_commit_option = 1; } if (patch_mode) { ret = stash_patch(info, ps, patch, quiet); if (ret < 0) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " "worktree state")); goto done; } else if (ret > 0) { goto done; } } else { if (stash_working_tree(info, ps)) { if (!quiet) fprintf_ln(stderr, _("Cannot save the current " "worktree state")); ret = -1; goto done; } } if (!stash_msg_buf->len) strbuf_addf(stash_msg_buf, "WIP on %s", msg.buf); else strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name); /* * `parents` will be empty after calling `commit_tree()`, so there is * no need to call `free_commit_list()` */ parents = NULL; if (untracked_commit_option) commit_list_insert(lookup_commit(the_repository, &info->u_commit), &parents); commit_list_insert(lookup_commit(the_repository, &info->i_commit), &parents); commit_list_insert(head_commit, &parents); if (commit_tree(stash_msg_buf->buf, stash_msg_buf->len, &info->w_tree, parents, &info->w_commit, NULL, NULL)) { if (!quiet) fprintf_ln(stderr, _("Cannot record " "working tree state")); ret = -1; goto done; } done: strbuf_release(&commit_tree_label); strbuf_release(&msg); strbuf_release(&untracked_files); return ret; }