static void rename_branch(const char *oldname, const char *newname, int force) { struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; unsigned char sha1[20]; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; int recovery = 0; if (!oldname) die("cannot rename the current branch while not on any."); if (strbuf_check_branch_ref(&oldref, oldname)) { /* * Bad name --- this could be an attempt to rename a * ref that we used to allow to be created by accident. */ if (resolve_ref(oldref.buf, sha1, 1, NULL)) recovery = 1; else die("Invalid branch name: '%s'", oldname); } if (strbuf_check_branch_ref(&newref, newname)) die("Invalid branch name: '%s'", newname); if (resolve_ref(newref.buf, sha1, 1, NULL) && !force) die("A branch named '%s' already exists.", newref.buf + 11); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); if (rename_ref(oldref.buf, newref.buf, logmsg.buf)) die("Branch rename failed"); strbuf_release(&logmsg); if (recovery) warning("Renamed a misnamed branch '%s' away", oldref.buf + 11); /* no need to pass logmsg here as HEAD didn't really move */ if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL)) die("Branch renamed to %s, but HEAD is not updated!", newname); strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11); strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", newref.buf + 11); strbuf_release(&newref); if (git_config_rename_section(oldsection.buf, newsection.buf) < 0) die("Branch is renamed, but update of config-file failed"); strbuf_release(&oldsection); strbuf_release(&newsection); }
int gidit_pushobj(FILE *fp, char * signingkey, int sign, unsigned int flags) { const char *head; unsigned char head_sha1[21]; struct gidit_refs_cb_data cbdata; struct strbuf buf = STRBUF_INIT; cbdata.buf = &buf; cbdata.flags = flags; head = resolve_ref("HEAD", head_sha1, 0, NULL); head_sha1[20] = '\0'; if (!head) { strbuf_release(&buf); return error("Failed to resolve HEAD as a valid ref."); } strbuf_add(&buf, sha1_to_hex(head_sha1), 40); strbuf_addstr(&buf, " HEAD\n"); for_each_ref(resolve_one_ref, &cbdata); if (sign) do_sign(&buf, signingkey); if (fwrite(buf.buf, buf.len, 1, fp) != 1) { strbuf_release(&buf); return error("Error while writing pushobj"); } strbuf_release(&buf); return 0; }
static void execute_commands(const char *unpacker_error) { struct command *cmd = commands; unsigned char sha1[20]; if (unpacker_error) { while (cmd) { cmd->error_string = "n/a (unpacker error)"; cmd = cmd->next; } return; } if (run_receive_hook(pre_receive_hook)) { while (cmd) { cmd->error_string = "pre-receive hook declined"; cmd = cmd->next; } return; } head_name = resolve_ref("HEAD", sha1, 0, NULL); while (cmd) { cmd->error_string = update(cmd); cmd = cmd->next; } }
static void execute_commands(struct command *commands, const char *unpacker_error) { struct command *cmd; unsigned char sha1[20]; if (unpacker_error) { for (cmd = commands; cmd; cmd = cmd->next) cmd->error_string = "n/a (unpacker error)"; return; } cmd = commands; if (check_everything_connected(iterate_receive_command_list, 0, &cmd)) set_connectivity_errors(commands); if (run_receive_hook(commands, pre_receive_hook, 0)) { for (cmd = commands; cmd; cmd = cmd->next) cmd->error_string = "pre-receive hook declined"; return; } check_aliased_updates(commands); free((char*)head_name); head_name = resolve_ref("HEAD", sha1, 0, NULL); if (head_name) head_name = xstrdup(head_name); for (cmd = commands; cmd; cmd = cmd->next) if (!cmd->skip_update) cmd->error_string = update(cmd); }
int fmt_merge_msg(struct strbuf *in, struct strbuf *out, struct fmt_merge_msg_opts *opts) { int i = 0, pos = 0; unsigned char head_sha1[20]; const char *current_branch; /* get current branch */ current_branch = resolve_ref("HEAD", head_sha1, 1, NULL); if (!current_branch) die("No current branch"); if (!prefixcmp(current_branch, "refs/heads/")) current_branch += 11; current_branch = xstrdup(current_branch); /* get a line */ while (pos < in->len) { int len; char *newline, *p = in->buf + pos; newline = strchr(p, '\n'); len = newline ? newline - p : strlen(p); pos += len + !!newline; i++; p[len] = 0; if (handle_line(p)) die ("Error in line %d: %.*s", i, len, p); } if (opts->add_title && srcs.nr) fmt_merge_msg_title(out, current_branch); if (origins.nr) fmt_merge_msg_sigs(out); if (opts->shortlog_len) { struct commit *head; struct rev_info rev; head = lookup_commit_or_die(head_sha1, "HEAD"); init_revisions(&rev, NULL); rev.commit_format = CMIT_FMT_ONELINE; rev.ignore_merges = 1; rev.limited = 1; if (suffixcmp(out->buf, "\n")) strbuf_addch(out, '\n'); for (i = 0; i < origins.nr; i++) shortlog(origins.items[i].string, origins.items[i].util, head, &rev, opts->shortlog_len, out); } strbuf_complete_line(out); free((char*)current_branch); return 0; }
int head_ref(each_ref_fn fn, void *cb_data) { unsigned char sha1[20]; int flag; if (resolve_ref("HEAD", sha1, 1, &flag)) return fn("HEAD", sha1, flag, cb_data); return 0; }
void wt_status_prepare(struct wt_status *s) { unsigned char sha1[20]; const char *head; memset(s, 0, sizeof(*s)); head = resolve_ref("HEAD", sha1, 0, NULL); s->branch = head ? xstrdup(head) : NULL; s->reference = "HEAD"; s->fp = stdout; s->index_file = get_index_file(); }
static int branch_merged(int kind, const char *name, struct commit *rev, struct commit *head_rev) { /* * This checks whether the merge bases of branch and HEAD (or * the other branch this branch builds upon) contains the * branch, which means that the branch has already been merged * safely to HEAD (or the other branch). */ struct commit *reference_rev = NULL; const char *reference_name = NULL; int merged; if (kind == REF_LOCAL_BRANCH) { struct branch *branch = branch_get(name); unsigned char sha1[20]; if (branch && branch->merge && branch->merge[0] && branch->merge[0]->dst && (reference_name = resolve_ref(branch->merge[0]->dst, sha1, 1, NULL)) != NULL) { reference_name = xstrdup(reference_name); reference_rev = lookup_commit_reference(sha1); } } if (!reference_rev) reference_rev = head_rev; merged = in_merge_bases(rev, &reference_rev, 1); /* * After the safety valve is fully redefined to "check with * upstream, if any, otherwise with HEAD", we should just * return the result of the in_merge_bases() above without * any of the following code, but during the transition period, * a gentle reminder is in order. */ if ((head_rev != reference_rev) && in_merge_bases(rev, &head_rev, 1) != merged) { if (merged) warning(_("deleting branch '%s' that has been merged to\n" " '%s', but not yet merged to HEAD."), name, reference_name); else warning(_("not deleting branch '%s' that is not yet merged to\n" " '%s', even though it is merged to HEAD."), name, reference_name); } free((char*)reference_name); return merged; }
static int rollback_single_pick(void) { unsigned char head_sha1[20]; if (!file_exists(git_path("CHERRY_PICK_HEAD")) && !file_exists(git_path("REVERT_HEAD"))) return error(_("no cherry-pick or revert in progress")); if (!resolve_ref("HEAD", head_sha1, 0, NULL)) return error(_("cannot resolve HEAD")); if (is_null_sha1(head_sha1)) return error(_("cannot abort from a branch yet to be born")); return reset_for_rollback(head_sha1); }
static char *resolve_symref(const char *src, const char *prefix) { unsigned char sha1[20]; int flag; const char *dst, *cp; dst = resolve_ref(src, sha1, 0, &flag); if (!(dst && (flag & REF_ISSYMREF))) return NULL; if (prefix && (cp = skip_prefix(dst, prefix))) dst = cp; return xstrdup(dst); }
static int is_ref_checked_out(const char *ref) { unsigned char sha1[20]; const char *head; if (is_bare_repository()) return 0; head = resolve_ref("HEAD", sha1, 0, NULL); if (!head) return 0; return !strcmp(head, ref); }
int head_ref_namespaced(each_ref_fn fn, void *cb_data) { struct strbuf buf = STRBUF_INIT; int ret = 0; unsigned char sha1[20]; int flag; strbuf_addf(&buf, "%sHEAD", get_git_namespace()); if (resolve_ref(buf.buf, sha1, 1, &flag)) ret = fn(buf.buf, sha1, flag, cb_data); strbuf_release(&buf); return ret; }
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[20]; char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41]; int flag; strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name); dst_name = resolve_ref(buf.buf, sha1, 0, &flag); strbuf_release(&buf); if (!(flag & REF_ISSYMREF)) return; dst_name = strip_namespace(dst_name); if (!dst_name) { rp_error("refusing update to broken symref '%s'", cmd->ref_name); cmd->skip_update = 1; cmd->error_string = "broken symref"; return; } 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; strcpy(cmd_oldh, find_unique_abbrev(cmd->old_sha1, DEFAULT_ABBREV)); strcpy(cmd_newh, find_unique_abbrev(cmd->new_sha1, DEFAULT_ABBREV)); strcpy(dst_oldh, find_unique_abbrev(dst_cmd->old_sha1, DEFAULT_ABBREV)); strcpy(dst_newh, find_unique_abbrev(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 int merge_commit(struct notes_merge_options *o) { struct strbuf msg = STRBUF_INIT; unsigned char sha1[20], parent_sha1[20]; struct notes_tree *t; struct commit *partial; struct pretty_print_context pretty_ctx; /* * Read partial merge result from .git/NOTES_MERGE_PARTIAL, * and target notes ref from .git/NOTES_MERGE_REF. */ if (get_sha1("NOTES_MERGE_PARTIAL", sha1)) die("Failed to read ref NOTES_MERGE_PARTIAL"); else if (!(partial = lookup_commit_reference(sha1))) die("Could not find commit from NOTES_MERGE_PARTIAL."); else if (parse_commit(partial)) die("Could not parse commit from NOTES_MERGE_PARTIAL."); if (partial->parents) hashcpy(parent_sha1, partial->parents->item->object.sha1); else hashclr(parent_sha1); t = xcalloc(1, sizeof(struct notes_tree)); init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0); o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL); if (!o->local_ref) die("Failed to resolve NOTES_MERGE_REF"); if (notes_merge_commit(o, t, partial, sha1)) die("Failed to finalize notes merge"); /* Reuse existing commit message in reflog message */ memset(&pretty_ctx, 0, sizeof(pretty_ctx)); format_commit_message(partial, "%s", &msg, &pretty_ctx); strbuf_trim(&msg); strbuf_insert(&msg, 0, "notes: ", 7); update_ref(msg.buf, o->local_ref, sha1, is_null_sha1(parent_sha1) ? NULL : parent_sha1, 0, DIE_ON_ERR); free_notes(t); strbuf_release(&msg); return merge_abort(o); }
static struct ref_lock *verify_lock(struct ref_lock *lock, const unsigned char *old_sha1, int mustexist) { if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist, NULL)) { error("Can't verify ref %s", lock->ref_name); unlock_ref(lock); return NULL; } if (hashcmp(lock->old_sha1, old_sha1)) { error("Ref %s is at %s but expected %s", lock->ref_name, sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1)); unlock_ref(lock); return NULL; } return lock; }
static void check_symref(const char *HEAD, int quiet) { unsigned char sha1[20]; int flag; const char *refs_heads_master = resolve_ref(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 int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data) { DIR *dir = opendir(git_path("logs/%s", base)); int retval = 0; if (dir) { struct dirent *de; int baselen = strlen(base); char *log = xmalloc(baselen + 257); memcpy(log, base, baselen); if (baselen && base[baselen-1] != '/') log[baselen++] = '/'; while ((de = readdir(dir)) != NULL) { struct stat st; int namelen; if (de->d_name[0] == '.') continue; namelen = strlen(de->d_name); if (namelen > 255) continue; if (has_extension(de->d_name, ".lock")) continue; memcpy(log + baselen, de->d_name, namelen+1); if (stat(git_path("logs/%s", log), &st) < 0) continue; if (S_ISDIR(st.st_mode)) { retval = do_for_each_reflog(log, fn, cb_data); } else { unsigned char sha1[20]; if (!resolve_ref(log, sha1, 0, NULL)) retval = error("bad ref for %s", log); else retval = fn(log, sha1, 0, cb_data); } if (retval) break; } free(log); closedir(dir); } else if (*base) return errno; return retval; }
static int warn_if_dangling_symref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct warn_if_dangling_data *d = cb_data; const char *resolves_to; unsigned char junk[20]; if (!(flags & REF_ISSYMREF)) return 0; resolves_to = resolve_ref(refname, junk, 0, NULL); if (!resolves_to || strcmp(resolves_to, d->refname)) return 0; fprintf(d->fp, d->msg_fmt, refname); return 0; }
static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data) { unsigned char sha1[20]; int flag; if (submodule) { if (resolve_gitlink_ref(submodule, "HEAD", sha1) == 0) return fn("HEAD", sha1, 0, cb_data); return 0; } if (resolve_ref("HEAD", sha1, 1, &flag)) return fn("HEAD", sha1, flag, cb_data); return 0; }
static void print_summary(const char *prefix, const unsigned char *sha1) { struct rev_info rev; struct commit *commit; static const char *format = "format:%h: \"%s\""; unsigned char junk_sha1[20]; const char *head = resolve_ref("HEAD", junk_sha1, 0, NULL); commit = lookup_commit(sha1); if (!commit) die("couldn't look up newly created commit"); 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; get_commit_format(format, &rev); 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("[%s%s]: created ", !prefixcmp(head, "refs/heads/") ? head + 11 : !strcmp(head, "HEAD") ? "detached HEAD" : head, initial_commit ? " (root-commit)" : ""); if (!log_tree_commit(&rev, commit)) { struct strbuf buf = STRBUF_INIT; format_commit_message(commit, format + 7, &buf, DATE_NORMAL); printf("%s\n", buf.buf); strbuf_release(&buf); } }
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_sha1(ref->new_sha1)) continue; /* Follow symbolic refs (mainly for HEAD). */ localname = ref->peer_ref->name; remotename = ref->name; tmp = resolve_ref(localname, sha, 1, &flag); if (tmp && flag & REF_ISSYMREF && !prefixcmp(tmp, "refs/heads/")) localname = tmp; /* Both source and destination must be local branches. */ if (!localname || prefixcmp(localname, "refs/heads/")) continue; if (!remotename || prefixcmp(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); } }
int peel_ref(const char *ref, unsigned char *sha1) { int flag; unsigned char base[20]; struct object *o; if (current_ref && (current_ref->name == ref || !strcmp(current_ref->name, ref))) { if (current_ref->flag & REF_KNOWS_PEELED) { hashcpy(sha1, current_ref->peeled); return 0; } hashcpy(base, current_ref->sha1); goto fallback; } if (!resolve_ref(ref, base, 1, &flag)) return -1; if ((flag & REF_ISPACKED)) { struct ref_list *list = get_packed_refs(NULL); while (list) { if (!strcmp(list->name, ref)) { if (list->flag & REF_KNOWS_PEELED) { hashcpy(sha1, list->peeled); return 0; } /* older pack-refs did not leave peeled ones */ break; } list = list->next; } } fallback: o = parse_object(base); if (o && o->type == OBJ_TAG) { o = deref_tag(o, ref, 0); if (o) { hashcpy(sha1, o->sha1); return 0; } } return -1; }
int comp_fini(bool status, mstr *obj, opctype retcode, oprtype *retopr, int src_len) { triple *ref; error_def(ERR_INDEXTRACHARS); if (status && source_column != src_len + 2 && source_buffer[source_column] != '\0') { status = FALSE; stx_error(ERR_INDEXTRACHARS); } if (status) { cg_phase = CGP_RESOLVE; assert(for_stack_ptr == for_stack); if (*for_stack_ptr) tnxtarg(*for_stack_ptr); ref = newtriple(retcode); if (retopr) ref->operand[0] = *retopr; start_fetches(OC_NOOP); resolve_ref(0); /* cannot fail because there are no MLAB_REF's in indirect code */ alloc_reg(); stp_gcol(0); assert(indr_stringpool.base == stringpool.base); indr_stringpool = stringpool; stringpool = rts_stringpool; compile_time = FALSE; ind_code(obj); indr_stringpool.free = indr_stringpool.base; } else { assert(indr_stringpool.base == stringpool.base); indr_stringpool = stringpool; stringpool = rts_stringpool; indr_stringpool.free = indr_stringpool.base; compile_time = FALSE; cg_phase = CGP_NOSTATE; } transform = TRUE; mcfree(); return status; }
static void read_config(void) { unsigned char sha1[20]; const char *head_ref; int flag; if (default_remote_name) // did this already return; default_remote_name = xstrdup("origin"); current_branch = NULL; head_ref = resolve_ref("HEAD", sha1, 0, &flag); if (head_ref && (flag & REF_ISSYMREF) && !prefixcmp(head_ref, "refs/heads/")) { current_branch = make_branch(head_ref + strlen("refs/heads/"), 0); } git_config(handle_config, NULL); alias_all_urls(); }
static struct ref_list *get_ref_dir(const char *base, struct ref_list *list) { DIR *dir = opendir(git_path("%s", base)); if (dir) { struct dirent *de; int baselen = strlen(base); char *ref = xmalloc(baselen + 257); memcpy(ref, base, baselen); if (baselen && base[baselen-1] != '/') ref[baselen++] = '/'; while ((de = readdir(dir)) != NULL) { unsigned char sha1[20]; struct stat st; int flag; int namelen; if (de->d_name[0] == '.') continue; namelen = strlen(de->d_name); if (namelen > 255) continue; if (has_extension(de->d_name, ".lock")) continue; memcpy(ref + baselen, de->d_name, namelen+1); if (stat(git_path("%s", ref), &st) < 0) continue; if (S_ISDIR(st.st_mode)) { list = get_ref_dir(ref, list); continue; } if (!resolve_ref(ref, sha1, 1, &flag)) { hashclr(sha1); flag |= REF_BROKEN; } list = add_ref(ref, sha1, flag, list, NULL); } free(ref); closedir(dir); } return sort_ref_list(list); }
static char *guess_ref(const char *name, struct ref *peer) { struct strbuf buf = STRBUF_INIT; unsigned char sha1[20]; const char *r = resolve_ref(peer->name, sha1, 1, NULL); if (!r) return NULL; if (!prefixcmp(r, "refs/heads/")) strbuf_addstr(&buf, "refs/heads/"); else if (!prefixcmp(r, "refs/tags/")) strbuf_addstr(&buf, "refs/tags/"); else return NULL; strbuf_addstr(&buf, name); return strbuf_detach(&buf, NULL); }
static void rename_branch(const char *oldname, const char *newname, int force) { struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT; unsigned char sha1[20]; struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; if (!oldname) die("cannot rename the current branch while not on any."); strbuf_addf(&oldref, "refs/heads/%s", oldname); if (check_ref_format(oldref.buf)) die("Invalid branch name: %s", oldref.buf); strbuf_addf(&newref, "refs/heads/%s", newname); if (check_ref_format(newref.buf)) die("Invalid branch name: %s", newref.buf); if (resolve_ref(newref.buf, sha1, 1, NULL) && !force) die("A branch named '%s' already exists.", newname); strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); if (rename_ref(oldref.buf, newref.buf, logmsg.buf)) die("Branch rename failed"); strbuf_release(&logmsg); /* no need to pass logmsg here as HEAD didn't really move */ if (!strcmp(oldname, head) && create_symref("HEAD", newref.buf, NULL)) die("Branch renamed to %s, but HEAD is not updated!", newname); strbuf_addf(&oldsection, "branch.%s", oldref.buf + 11); strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", newref.buf + 11); strbuf_release(&newref); if (git_config_rename_section(oldsection.buf, newsection.buf) < 0) die("Branch is renamed, but update of config-file failed"); strbuf_release(&oldsection); strbuf_release(&newsection); }
void wt_status_prepare(struct wt_status *s) { unsigned char sha1[20]; const char *head; memset(s, 0, sizeof(*s)); memcpy(s->color_palette, default_wt_status_colors, sizeof(default_wt_status_colors)); s->show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; s->use_color = -1; s->relative_paths = 1; head = resolve_ref("HEAD", sha1, 0, NULL); s->branch = head ? xstrdup(head) : NULL; s->reference = "HEAD"; s->fp = stdout; s->index_file = get_index_file(); s->change.strdup_strings = 1; s->untracked.strdup_strings = 1; s->ignored.strdup_strings = 1; }
int gidit_gen_bundle(FILE *fp, unsigned int flags) { unsigned char head_sha1[20]; struct child_process rls; struct pushobj po = PO_INIT; const char *head; char **argv = xmalloc(6 * sizeof(char *)); // const char **argv_pack = xmalloc(5 * sizeof(const char *)); read_pobj(fp, &po); if (verify_pushobj(&po)) die("Failed verification"); // look up current head head = resolve_ref("HEAD", head_sha1, 0, NULL); // generate bundle memset(&rls, 0, sizeof(rls)); argv[0] = "bundle"; argv[1] = "create"; argv[2] = "-"; argv[3] = "--branches"; argv[4] = xmalloc(sizeof(char) * (40 + 40 + 2 + 1)); argv[5] = NULL; sprintf(argv[4], "%s..%s", po.head, sha1_to_hex(head_sha1)); pobj_release(&po); rls.argv = argv; rls.git_cmd = 1; if (run_command(&rls)) return -1; return 0; }
int cmd_show_branch(int ac, const char **av, const char *prefix) { struct commit *rev[MAX_REVS], *commit; char *reflog_msg[MAX_REVS]; struct commit_list *list = NULL, *seen = NULL; unsigned int rev_mask[MAX_REVS]; int num_rev, i, extra = 0; int all_heads = 0, all_remotes = 0; int all_mask, all_revs; int lifo = 1; char head[128]; const char *head_p; int head_len; unsigned char head_sha1[20]; int merge_base = 0; int independent = 0; int no_name = 0; int sha1_name = 0; int shown_merge_point = 0; int with_current_branch = 0; int head_at = -1; int topics = 0; int dense = 1; const char *reflog_base = NULL; struct option builtin_show_branch_options[] = { OPT_BOOLEAN('a', "all", &all_heads, "show remote-tracking and local branches"), OPT_BOOLEAN('r', "remotes", &all_remotes, "show remote-tracking branches"), OPT__COLOR(&showbranch_use_color, "color '*!+-' corresponding to the branch"), { OPTION_INTEGER, 0, "more", &extra, "n", "show <n> more commits after the common ancestor", PARSE_OPT_OPTARG, NULL, (intptr_t)1 }, OPT_SET_INT(0, "list", &extra, "synonym to more=-1", -1), OPT_BOOLEAN(0, "no-name", &no_name, "suppress naming strings"), OPT_BOOLEAN(0, "current", &with_current_branch, "include the current branch"), OPT_BOOLEAN(0, "sha1-name", &sha1_name, "name commits with their object names"), OPT_BOOLEAN(0, "merge-base", &merge_base, "show possible merge bases"), OPT_BOOLEAN(0, "independent", &independent, "show refs unreachable from any other ref"), OPT_BOOLEAN(0, "topo-order", &lifo, "show commits in topological order"), OPT_BOOLEAN(0, "topics", &topics, "show only commits not on the first branch"), OPT_SET_INT(0, "sparse", &dense, "show merges reachable from only one tip", 0), OPT_SET_INT(0, "date-order", &lifo, "show commits where no parent comes before its " "children", 0), { OPTION_CALLBACK, 'g', "reflog", &reflog_base, "<n>[,<base>]", "show <n> most recent ref-log entries starting at " "base", PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parse_reflog_param }, OPT_END() }; git_config(git_show_branch_config, NULL); if (showbranch_use_color == -1) showbranch_use_color = git_use_color_default; /* If nothing is specified, try the default first */ if (ac == 1 && default_num) { ac = default_num; av = default_arg; } ac = parse_options(ac, av, prefix, builtin_show_branch_options, show_branch_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (all_heads) all_remotes = 1; if (extra || reflog) { /* "listing" mode is incompatible with * independent nor merge-base modes. */ if (independent || merge_base) usage_with_options(show_branch_usage, builtin_show_branch_options); if (reflog && ((0 < extra) || all_heads || all_remotes)) /* * Asking for --more in reflog mode does not * make sense. --list is Ok. * * Also --all and --remotes do not make sense either. */ die("--reflog is incompatible with --all, --remotes, " "--independent or --merge-base"); } /* If nothing is specified, show all branches by default */ if (ac + all_heads + all_remotes == 0) all_heads = 1; if (reflog) { unsigned char sha1[20]; char nth_desc[256]; char *ref; int base = 0; if (ac == 0) { static const char *fake_av[2]; const char *refname; refname = resolve_ref("HEAD", sha1, 1, NULL); fake_av[0] = xstrdup(refname); fake_av[1] = NULL; av = fake_av; ac = 1; } if (ac != 1) die("--reflog option needs one branch name"); if (MAX_REVS < reflog) die("Only %d entries can be shown at one time.", MAX_REVS); if (!dwim_ref(*av, strlen(*av), sha1, &ref)) die("No such ref %s", *av); /* Has the base been specified? */ if (reflog_base) { char *ep; base = strtoul(reflog_base, &ep, 10); if (*ep) { /* Ah, that is a date spec... */ unsigned long at; at = approxidate(reflog_base); read_ref_at(ref, at, -1, sha1, NULL, NULL, NULL, &base); } } for (i = 0; i < reflog; i++) { char *logmsg, *m; const char *msg; unsigned long timestamp; int tz; if (read_ref_at(ref, 0, base+i, sha1, &logmsg, ×tamp, &tz, NULL)) { reflog = i; break; } msg = strchr(logmsg, '\t'); if (!msg) msg = "(none)"; else msg++; m = xmalloc(strlen(msg) + 200); sprintf(m, "(%s) %s", show_date(timestamp, tz, 1), msg); reflog_msg[i] = m; free(logmsg); sprintf(nth_desc, "%s@{%d}", *av, base+i); append_ref(nth_desc, sha1, 1); } } else if (all_heads + all_remotes) snarf_refs(all_heads, all_remotes); else { while (0 < ac) { append_one_rev(*av); ac--; av++; } } head_p = resolve_ref("HEAD", head_sha1, 1, NULL); if (head_p) { head_len = strlen(head_p); memcpy(head, head_p, head_len + 1); } else { head_len = 0; head[0] = 0; } if (with_current_branch && head_p) { int has_head = 0; for (i = 0; !has_head && i < ref_name_cnt; i++) { /* We are only interested in adding the branch * HEAD points at. */ if (rev_is_head(head, head_len, ref_name[i], head_sha1, NULL)) has_head++; } if (!has_head) { int offset = !prefixcmp(head, "refs/heads/") ? 11 : 0; append_one_rev(head + offset); } } if (!ref_name_cnt) { fprintf(stderr, "No revs to be shown.\n"); exit(0); } for (num_rev = 0; ref_name[num_rev]; num_rev++) { unsigned char revkey[20]; unsigned int flag = 1u << (num_rev + REV_SHIFT); if (MAX_REVS <= num_rev) die("cannot handle more than %d revs.", MAX_REVS); if (get_sha1(ref_name[num_rev], revkey)) die("'%s' is not a valid ref.", ref_name[num_rev]); commit = lookup_commit_reference(revkey); if (!commit) die("cannot find commit %s (%s)", ref_name[num_rev], revkey); parse_commit(commit); mark_seen(commit, &seen); /* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1, * and so on. REV_SHIFT bits from bit 0 are used for * internal bookkeeping. */ commit->object.flags |= flag; if (commit->object.flags == flag) commit_list_insert_by_date(commit, &list); rev[num_rev] = commit; } for (i = 0; i < num_rev; i++) rev_mask[i] = rev[i]->object.flags; if (0 <= extra) join_revs(&list, &seen, num_rev, extra); commit_list_sort_by_date(&seen); if (merge_base) return show_merge_base(seen, num_rev); if (independent) return show_independent(rev, num_rev, ref_name, rev_mask); /* Show list; --more=-1 means list-only */ if (1 < num_rev || extra < 0) { for (i = 0; i < num_rev; i++) { int j; int is_head = rev_is_head(head, head_len, ref_name[i], head_sha1, rev[i]->object.sha1); if (extra < 0) printf("%c [%s] ", is_head ? '*' : ' ', ref_name[i]); else { for (j = 0; j < i; j++) putchar(' '); printf("%s%c%s [%s] ", get_color_code(i % COLUMN_COLORS_MAX), is_head ? '*' : '!', get_color_reset_code(), ref_name[i]); } if (!reflog) { /* header lines never need name */ show_one_commit(rev[i], 1); } else puts(reflog_msg[i]); if (is_head) head_at = i; } if (0 <= extra) { for (i = 0; i < num_rev; i++) putchar('-'); putchar('\n'); } } if (extra < 0) exit(0); /* Sort topologically */ sort_in_topological_order(&seen, lifo); /* Give names to commits */ if (!sha1_name && !no_name) name_commits(seen, rev, ref_name, num_rev); all_mask = ((1u << (REV_SHIFT + num_rev)) - 1); all_revs = all_mask & ~((1u << REV_SHIFT) - 1); while (seen) { struct commit *commit = pop_one_commit(&seen); int this_flag = commit->object.flags; int is_merge_point = ((this_flag & all_revs) == all_revs); shown_merge_point |= is_merge_point; if (1 < num_rev) { int is_merge = !!(commit->parents && commit->parents->next); if (topics && !is_merge_point && (this_flag & (1u << REV_SHIFT))) continue; if (dense && is_merge && omit_in_dense(commit, rev, num_rev)) continue; for (i = 0; i < num_rev; i++) { int mark; if (!(this_flag & (1u << (i + REV_SHIFT)))) mark = ' '; else if (is_merge) mark = '-'; else if (i == head_at) mark = '*'; else mark = '+'; printf("%s%c%s", get_color_code(i % COLUMN_COLORS_MAX), mark, get_color_reset_code()); } putchar(' '); } show_one_commit(commit, no_name); if (shown_merge_point && --extra < 0) break; } return 0; }