int not_pushed(struct commit *current_head){ struct commit *remote_head; unsigned char sha1[20]; const struct name_decoration decoration; int decoration_style=1; if (decoration_style) { load_ref_decorations(decoration_style); } decoration = get_name_decoration(¤t_head->object); const char* upstream = (branch_get(NULL)->merge)?branch_get(NULL)->merge[0]->dst : NULL; if (upstream==NULL) return (int)true; if (get_sha1(upstream, sha1)) remote_head = NULL; else { remote_head = lookup_commit_or_die(sha1, upstream); if (parse_commit(remote_head)) die(_("could not parse remote head commit")); } struct commit *old_ci=remote_head,*new_ci=current_head; if (old_ci->date > new_ci->date){ struct commit *tmp = old_ci; old_ci=new_ci; new_ci=tmp; } }
static void setup_default_push_refspecs(struct remote *remote) { struct branch *branch = branch_get(NULL); int triangular = is_workflow_triangular(remote); switch (push_default) { default: case PUSH_DEFAULT_MATCHING: add_refspec(":"); break; case PUSH_DEFAULT_UNSPECIFIED: case PUSH_DEFAULT_SIMPLE: if (triangular) setup_push_current(remote, branch); else setup_push_upstream(remote, branch, triangular, 1); break; case PUSH_DEFAULT_UPSTREAM: setup_push_upstream(remote, branch, triangular, 0); break; case PUSH_DEFAULT_CURRENT: setup_push_current(remote, branch); break; case PUSH_DEFAULT_NOTHING: die(_("You didn't specify any refspecs to push, and " "push.default is \"nothing\".")); break; } }
static void setup_push_upstream(struct remote *remote) { struct strbuf refspec = STRBUF_INIT; struct branch *branch = branch_get(NULL); if (!branch) die(_("You are not currently on a branch.\n" "To push the history leading to the current (detached HEAD)\n" "state now, use\n" "\n" " git push %s HEAD:<name-of-remote-branch>\n"), remote->name); if (!branch->merge_nr || !branch->merge) die(_("The current branch %s has no upstream branch.\n" "To push the current branch and set the remote as upstream, use\n" "\n" " git push --set-upstream %s %s\n"), branch->name, remote->name, branch->name); if (branch->merge_nr != 1) die(_("The current branch %s has multiple upstream branches, " "refusing to push."), branch->name); strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src); add_refspec(refspec.buf); }
static void setup_push_upstream(struct remote *remote, int simple) { struct strbuf refspec = STRBUF_INIT; struct branch *branch = branch_get(NULL); if (!branch) die(_("You are not currently on a branch.\n" "To push the history leading to the current (detached HEAD)\n" "state now, use\n" "\n" " git push %s HEAD:<name-of-remote-branch>\n"), remote->name); if (!branch->merge_nr || !branch->merge || !branch->remote_name) die(_("The current branch %s has no upstream branch.\n" "To push the current branch and set the remote as upstream, use\n" "\n" " git push --set-upstream %s %s\n"), branch->name, remote->name, branch->name); if (branch->merge_nr != 1) die(_("The current branch %s has multiple upstream branches, " "refusing to push."), branch->name); if (strcmp(branch->remote_name, remote->name)) die(_("You are pushing to remote '%s', which is not the upstream of\n" "your current branch '%s', without telling me what to push\n" "to update which remote branch."), remote->name, branch->name); if (simple && strcmp(branch->refname, branch->merge[0]->src)) die_push_simple(branch, remote); strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src); add_refspec(refspec.buf); }
static const char *map_refspec(const char *ref, struct remote *remote, struct ref *local_refs) { struct ref *matched = NULL; /* Does "ref" uniquely name our ref? */ if (count_refspec_match(ref, local_refs, &matched) != 1) return ref; if (remote->push.nr) { struct refspec_item query; memset(&query, 0, sizeof(struct refspec_item)); query.src = matched->name; if (!query_refspecs(&remote->push, &query) && query.dst) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s%s:%s", query.force ? "+" : "", query.src, query.dst); return strbuf_detach(&buf, NULL); } } if (push_default == PUSH_DEFAULT_UPSTREAM && starts_with(matched->name, "refs/heads/")) { struct branch *branch = branch_get(matched->name + 11); if (branch->merge_nr == 1 && branch->merge[0]->src) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s:%s", ref, branch->merge[0]->src); return strbuf_detach(&buf, NULL); } } return ref; }
static void wt_status_print_tracking(struct wt_status *s) { struct strbuf sb = STRBUF_INIT; const char *cp, *ep; struct branch *branch; char comment_line_string[3]; int i; assert(s->branch && !s->is_initial); if (!starts_with(s->branch, "refs/heads/")) return; branch = branch_get(s->branch + 11); if (!format_tracking_info(branch, &sb)) return; i = 0; if (s->display_comment_prefix) { comment_line_string[i++] = comment_line_char; comment_line_string[i++] = ' '; } comment_line_string[i] = '\0'; for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%s%.*s", comment_line_string, (int)(ep - cp), cp); if (s->display_comment_prefix) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c", comment_line_char); else fputs("", s->fp); }
static void fill_tracking_info(struct strbuf *stat, const char *branch_name, int show_upstream_ref) { int ours, theirs; struct branch *branch = branch_get(branch_name); if (!stat_tracking_info(branch, &ours, &theirs)) { if (branch && branch->merge && branch->merge[0]->dst && show_upstream_ref) strbuf_addf(stat, "[%s] ", shorten_unambiguous_ref(branch->merge[0]->dst, 0)); return; } strbuf_addch(stat, '['); if (show_upstream_ref) strbuf_addf(stat, "%s: ", shorten_unambiguous_ref(branch->merge[0]->dst, 0)); if (!ours) strbuf_addf(stat, "behind %d] ", theirs); else if (!theirs) strbuf_addf(stat, "ahead %d] ", ours); else strbuf_addf(stat, "ahead %d, behind %d] ", ours, theirs); }
static struct branch *get_current_branch(struct remote *remote) { struct branch *branch = branch_get(NULL); if (!branch) die(_(message_detached_head_die), remote->name); return branch; }
static struct ref *get_ref_map(struct transport *transport, struct refspec *refs, int ref_count, int tags, int *autotags) { int i; struct ref *rm; struct ref *ref_map = NULL; struct ref **tail = &ref_map; const struct ref *remote_refs = transport_get_remote_refs(transport); if (ref_count || tags == TAGS_SET) { for (i = 0; i < ref_count; i++) { get_fetch_map(remote_refs, &refs[i], &tail, 0); if (refs[i].dst && refs[i].dst[0]) *autotags = 1; } /* Merge everything on the command line, but not --tags */ for (rm = ref_map; rm; rm = rm->next) rm->merge = 1; if (tags == TAGS_SET) get_fetch_map(remote_refs, tag_refspec, &tail, 0); } else { /* Use the defaults */ struct remote *remote = transport->remote; struct branch *branch = branch_get(NULL); int has_merge = branch_has_merge_config(branch); if (remote && (remote->fetch_refspec_nr || has_merge)) { for (i = 0; i < remote->fetch_refspec_nr; i++) { get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0); if (remote->fetch[i].dst && remote->fetch[i].dst[0]) *autotags = 1; if (!i && !has_merge && ref_map && !remote->fetch[0].pattern) ref_map->merge = 1; } /* * if the remote we're fetching from is the same * as given in branch.<name>.remote, we add the * ref given in branch.<name>.merge, too. */ if (has_merge && !strcmp(branch->remote_name, remote->name)) add_merge_config(&ref_map, remote_refs, branch, &tail); } else { ref_map = get_remote_ref(remote_refs, "HEAD"); if (!ref_map) die("Couldn't find remote ref HEAD"); ref_map->merge = 1; tail = &ref_map->next; } } if (tags == TAGS_DEFAULT && *autotags) find_non_local_tags(transport, &ref_map, &tail); ref_remove_duplicates(ref_map); return ref_map; }
static void wt_shortstatus_print_tracking(struct wt_status *s) { struct branch *branch; const char *header_color = color(WT_STATUS_HEADER, s); const char *branch_color_local = color(WT_STATUS_LOCAL_BRANCH, s); const char *branch_color_remote = color(WT_STATUS_REMOTE_BRANCH, s); const char *base; const char *branch_name; int num_ours, num_theirs; color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## "); if (!s->branch) return; branch_name = s->branch; if (!prefixcmp(branch_name, "refs/heads/")) branch_name += 11; else if (!strcmp(branch_name, "HEAD")) { branch_name = _("HEAD (no branch)"); branch_color_local = color(WT_STATUS_NOBRANCH, s); } branch = branch_get(s->branch + 11); if (s->is_initial) color_fprintf(s->fp, header_color, _("Initial commit on ")); if (!stat_tracking_info(branch, &num_ours, &num_theirs)) { color_fprintf(s->fp, branch_color_local, "%s", branch_name); fputc(s->null_termination ? '\0' : '\n', s->fp); return; } base = branch->merge[0]->dst; base = shorten_unambiguous_ref(base, 0); color_fprintf(s->fp, branch_color_local, "%s", branch_name); color_fprintf(s->fp, header_color, "..."); color_fprintf(s->fp, branch_color_remote, "%s", base); color_fprintf(s->fp, header_color, " ["); if (!num_ours) { color_fprintf(s->fp, header_color, _("behind ")); color_fprintf(s->fp, branch_color_remote, "%d", num_theirs); } else if (!num_theirs) { color_fprintf(s->fp, header_color, _("ahead ")); color_fprintf(s->fp, branch_color_local, "%d", num_ours); } else { color_fprintf(s->fp, header_color, _("ahead ")); color_fprintf(s->fp, branch_color_local, "%d", num_ours); color_fprintf(s->fp, header_color, _(", behind ")); color_fprintf(s->fp, branch_color_remote, "%d", num_theirs); } color_fprintf(s->fp, header_color, "]"); fputc(s->null_termination ? '\0' : '\n', s->fp); }
static void report_tracking(struct branch_info *new_branch_info) { struct strbuf sb = STRBUF_INIT; struct branch *branch = branch_get(new_branch_info->name); if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL)) return; fputs(sb.buf, stdout); strbuf_release(&sb); }
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; void *reference_name_to_free = 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 = reference_name_to_free = resolve_refdup(branch->merge[0]->dst, RESOLVE_REF_READING, sha1, NULL)) != NULL) reference_rev = lookup_commit_reference(sha1); } if (!reference_rev) reference_rev = head_rev; merged = in_merge_bases(rev, reference_rev); /* * 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) != 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(reference_name_to_free); return merged; }
/** * Dies with the appropriate reason for why there are no merge candidates: * * 1. We fetched from a specific remote, and a refspec was given, but it ended * up not fetching anything. This is usually because the user provided a * wildcard refspec which had no matches on the remote end. * * 2. We fetched from a non-default remote, but didn't specify a branch to * merge. We can't use the configured one because it applies to the default * remote, thus the user must specify the branches to merge. * * 3. We fetched from the branch's or repo's default remote, but: * * a. We are not on a branch, so there will never be a configured branch to * merge with. * * b. We are on a branch, but there is no configured branch to merge with. * * 4. We fetched from the branch's or repo's default remote, but the configured * branch to merge didn't get fetched. (Either it doesn't exist, or wasn't * part of the configured fetch refspec.) */ static void NORETURN die_no_merge_candidates(const char *repo, const char **refspecs) { struct branch *curr_branch = branch_get("HEAD"); const char *remote = curr_branch ? curr_branch->remote_name : NULL; if (*refspecs) { if (opt_rebase) fprintf_ln(stderr, _("There is no candidate for rebasing against among the refs that you just fetched.")); else fprintf_ln(stderr, _("There are no candidates for merging among the refs that you just fetched.")); fprintf_ln(stderr, _("Generally this means that you provided a wildcard refspec which had no\n" "matches on the remote end.")); } else if (repo && curr_branch && (!remote || strcmp(repo, remote))) { fprintf_ln(stderr, _("You asked to pull from the remote '%s', but did not specify\n" "a branch. Because this is not the default configured remote\n" "for your current branch, you must specify a branch on the command line."), repo); } else if (!curr_branch) { fprintf_ln(stderr, _("You are not currently on a branch.")); if (opt_rebase) fprintf_ln(stderr, _("Please specify which branch you want to rebase against.")); else fprintf_ln(stderr, _("Please specify which branch you want to merge with.")); fprintf_ln(stderr, _("See git-pull(1) for details.")); fprintf(stderr, "\n"); fprintf_ln(stderr, " git pull %s %s", _("<remote>"), _("<branch>")); fprintf(stderr, "\n"); } else if (!curr_branch->merge_nr) { const char *remote_name = NULL; if (for_each_remote(get_only_remote, &remote_name) || !remote_name) remote_name = _("<remote>"); fprintf_ln(stderr, _("There is no tracking information for the current branch.")); if (opt_rebase) fprintf_ln(stderr, _("Please specify which branch you want to rebase against.")); else fprintf_ln(stderr, _("Please specify which branch you want to merge with.")); fprintf_ln(stderr, _("See git-pull(1) for details.")); fprintf(stderr, "\n"); fprintf_ln(stderr, " git pull %s %s", _("<remote>"), _("<branch>")); fprintf(stderr, "\n"); fprintf_ln(stderr, _("If you wish to set tracking information for this branch you can do so with:")); fprintf(stderr, "\n"); fprintf_ln(stderr, " git branch --set-upstream-to=%s/%s %s\n", remote_name, _("<branch>"), curr_branch->name); } else fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n" "from the remote, but no such ref was fetched."), *curr_branch->merge_name); exit(1); }
static void check_not_current_branch(struct ref *ref_map) { struct branch *current_branch = branch_get(NULL); if (is_bare_repository() || !current_branch) return; for (; ref_map; ref_map = ref_map->next) if (ref_map->peer_ref && !strcmp(current_branch->refname, ref_map->peer_ref->name)) die("Refusing to fetch into current branch %s " "of non-bare repository", current_branch->refname); }
static void fill_tracking_info(struct strbuf *stat, const char *branch_name) { int ours, theirs; struct branch *branch = branch_get(branch_name); if (!stat_tracking_info(branch, &ours, &theirs) || (!ours && !theirs)) return; if (!ours) strbuf_addf(stat, "[behind %d] ", theirs); else if (!theirs) strbuf_addf(stat, "[ahead %d] ", ours); else strbuf_addf(stat, "[ahead %d, behind %d] ", ours, theirs); }
static void setup_push_tracking(void) { struct strbuf refspec = STRBUF_INIT; struct branch *branch = branch_get(NULL); if (!branch) die("You are not currently on a branch."); if (!branch->merge_nr) die("The current branch %s is not tracking anything.", branch->name); if (branch->merge_nr != 1) die("The current branch %s is tracking multiple branches, " "refusing to push.", branch->name); strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src); add_refspec(refspec.buf); }
static void wt_status_print_tracking(struct wt_status *s) { struct strbuf sb = STRBUF_INIT; const char *cp, *ep; struct branch *branch; assert(s->branch && !s->is_initial); if (prefixcmp(s->branch, "refs/heads/")) return; branch = branch_get(s->branch + 11); if (!format_tracking_info(branch, &sb)) return; for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1) color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# %.*s", (int)(ep - cp), cp); color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#"); }
/** * Returns the default configured value for --rebase. It first looks for the * value of "branch.$curr_branch.rebase", where $curr_branch is the current * branch, and if HEAD is detached or the configuration key does not exist, * looks for the value of "pull.rebase". If both configuration keys do not * exist, returns REBASE_FALSE. */ static enum rebase_type config_get_rebase(void) { struct branch *curr_branch = branch_get("HEAD"); const char *value; if (curr_branch) { char *key = xstrfmt("branch.%s.rebase", curr_branch->name); if (!git_config_get_value(key, &value)) { enum rebase_type ret = parse_config_rebase(key, value, 1); free(key); return ret; } free(key); } if (!git_config_get_value("pull.rebase", &value)) return parse_config_rebase("pull.rebase", value, 1); return REBASE_FALSE; }
/** * Given the repo and refspecs, sets fork_point to the point at which the * current branch forked from its remote-tracking branch. Returns 0 on success, * -1 on failure. */ static int get_rebase_fork_point(struct object_id *fork_point, const char *repo, const char *refspec) { int ret; struct branch *curr_branch; const char *remote_branch; struct child_process cp = CHILD_PROCESS_INIT; struct strbuf sb = STRBUF_INIT; curr_branch = branch_get("HEAD"); if (!curr_branch) return -1; if (refspec) remote_branch = get_tracking_branch(repo, refspec); else remote_branch = get_upstream_branch(repo); if (!remote_branch) return -1; argv_array_pushl(&cp.args, "merge-base", "--fork-point", remote_branch, curr_branch->name, NULL); cp.no_stdin = 1; cp.no_stderr = 1; cp.git_cmd = 1; ret = capture_command(&cp, &sb, GIT_SHA1_HEXSZ); if (ret) goto cleanup; ret = get_oid_hex(sb.buf, fork_point); if (ret) goto cleanup; cleanup: strbuf_release(&sb); return ret ? -1 : 0; }
static void fill_tracking_info(struct strbuf *stat, const char *branch_name, int show_upstream_ref) { int ours, theirs; char *ref = NULL; struct branch *branch = branch_get(branch_name); if (!stat_tracking_info(branch, &ours, &theirs)) { if (branch && branch->merge && branch->merge[0]->dst && show_upstream_ref) strbuf_addf(stat, "[%s] ", shorten_unambiguous_ref(branch->merge[0]->dst, 0)); return; } if (show_upstream_ref) ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0); if (!ours) { if (ref) strbuf_addf(stat, _("[%s: behind %d]"), ref, theirs); else strbuf_addf(stat, _("[behind %d]"), theirs); } else if (!theirs) { if (ref) strbuf_addf(stat, _("[%s: ahead %d]"), ref, ours); else strbuf_addf(stat, _("[ahead %d]"), ours); } else { if (ref) strbuf_addf(stat, _("[%s: ahead %d, behind %d]"), ref, ours, theirs); else strbuf_addf(stat, _("[ahead %d, behind %d]"), ours, theirs); } strbuf_addch(stat, ' '); free(ref); }
/** * Returns remote's upstream branch for the current branch. If remote is NULL, * the current branch's configured default remote is used. Returns NULL if * `remote` does not name a valid remote, HEAD does not point to a branch, * remote is not the branch's configured remote or the branch does not have any * configured upstream branch. */ static const char *get_upstream_branch(const char *remote) { struct remote *rm; struct branch *curr_branch; const char *curr_branch_remote; rm = remote_get(remote); if (!rm) return NULL; curr_branch = branch_get("HEAD"); if (!curr_branch) return NULL; curr_branch_remote = remote_for_branch(curr_branch, NULL); assert(curr_branch_remote); if (strcmp(curr_branch_remote, rm->name)) return NULL; return branch_get_upstream(curr_branch, NULL); }
/* * Pretend as if the user told us to merge with the tracking * branch we have for the upstream of the current branch */ static int setup_with_upstream(const char ***argv) { struct branch *branch = branch_get(NULL); int i; const char **args; if (!branch) die(_("No current branch.")); if (!branch->remote) die(_("No remote for the current branch.")); if (!branch->merge_nr) die(_("No default upstream defined for the current branch.")); args = xcalloc(branch->merge_nr + 1, sizeof(char *)); for (i = 0; i < branch->merge_nr; i++) { if (!branch->merge[i]->dst) die(_("No remote tracking branch for %s from %s"), branch->merge[i]->src, branch->remote_name); args[i] = branch->merge[i]->dst; } args[i] = NULL; *argv = args; return i; }
static struct commit *get_base_commit(const char *base_commit, struct commit **list, int total) { struct commit *base = NULL; struct commit **rev; int i = 0, rev_nr = 0; if (base_commit && strcmp(base_commit, "auto")) { base = lookup_commit_reference_by_name(base_commit); if (!base) die(_("Unknown commit %s"), base_commit); } else if ((base_commit && !strcmp(base_commit, "auto")) || base_auto) { struct branch *curr_branch = branch_get(NULL); const char *upstream = branch_get_upstream(curr_branch, NULL); if (upstream) { struct commit_list *base_list; struct commit *commit; unsigned char sha1[20]; if (get_sha1(upstream, sha1)) die(_("Failed to resolve '%s' as a valid ref."), upstream); commit = lookup_commit_or_die(sha1, "upstream base"); base_list = get_merge_bases_many(commit, total, list); /* There should be one and only one merge base. */ if (!base_list || base_list->next) die(_("Could not find exact merge base.")); base = base_list->item; free_commit_list(base_list); } else { die(_("Failed to get upstream, if you want to record base commit automatically,\n" "please use git branch --set-upstream-to to track a remote branch.\n" "Or you could specify base commit by --base=<base-commit-id> manually.")); } } ALLOC_ARRAY(rev, total); for (i = 0; i < total; i++) rev[i] = list[i]; rev_nr = total; /* * Get merge base through pair-wise computations * and store it in rev[0]. */ while (rev_nr > 1) { for (i = 0; i < rev_nr / 2; i++) { struct commit_list *merge_base; merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]); if (!merge_base || merge_base->next) die(_("Failed to find exact merge base")); rev[i] = merge_base->item; } if (rev_nr % 2) rev[i] = rev[2 * i]; rev_nr = (rev_nr + 1) / 2; } if (!in_merge_bases(base, rev[0])) die(_("base commit should be the ancestor of revision list")); for (i = 0; i < total; i++) { if (base == list[i]) die(_("base commit shouldn't be in revision list")); } free(rev); return base; }
int cmd_cherry(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct patch_ids ids; struct commit *commit; struct commit_list *list = NULL; struct branch *current_branch; const char *upstream; const char *head = "HEAD"; const char *limit = NULL; int verbose = 0; if (argc > 1 && !strcmp(argv[1], "-v")) { verbose = 1; argc--; argv++; } if (argc > 1 && !strcmp(argv[1], "-h")) usage(cherry_usage); switch (argc) { case 4: limit = argv[3]; /* FALLTHROUGH */ case 3: head = argv[2]; /* FALLTHROUGH */ case 2: upstream = argv[1]; break; default: current_branch = branch_get(NULL); if (!current_branch || !current_branch->merge || !current_branch->merge[0] || !current_branch->merge[0]->dst) { fprintf(stderr, "Could not find a tracked" " remote branch, please" " specify <upstream> manually.\n"); usage(cherry_usage); } upstream = current_branch->merge[0]->dst; } init_revisions(&revs, prefix); revs.diff = 1; revs.combine_merges = 0; revs.ignore_merges = 1; DIFF_OPT_SET(&revs.diffopt, RECURSIVE); if (add_pending_commit(head, &revs, 0)) die("Unknown commit %s", head); if (add_pending_commit(upstream, &revs, UNINTERESTING)) die("Unknown commit %s", upstream); /* Don't say anything if head and upstream are the same. */ if (revs.pending.nr == 2) { struct object_array_entry *o = revs.pending.objects; if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0) return 0; } get_patch_ids(&revs, &ids, prefix); if (limit && add_pending_commit(limit, &revs, UNINTERESTING)) die("Unknown commit %s", limit); /* reverse the list of commits */ if (prepare_revision_walk(&revs)) die("revision walk setup failed"); while ((commit = get_revision(&revs)) != NULL) { /* ignore merges */ if (commit->parents && commit->parents->next) continue; commit_list_insert(commit, &list); } while (list) { char sign = '+'; commit = list->item; if (has_commit_patch_id(commit, &ids)) sign = '-'; if (verbose) { struct strbuf buf = STRBUF_INIT; struct pretty_print_context ctx = {0}; pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx); printf("%c %s %s\n", sign, sha1_to_hex(commit->object.sha1), buf.buf); strbuf_release(&buf); } else { printf("%c %s\n", sign, sha1_to_hex(commit->object.sha1)); } list = list->next; } free_patch_ids(&ids); return 0; }
int cmd_cherry(int argc, const char **argv, const char *prefix) { struct rev_info revs; struct patch_ids ids; struct commit *commit; struct commit_list *list = NULL; struct branch *current_branch; const char *upstream; const char *head = "HEAD"; const char *limit = NULL; int verbose = 0, abbrev = 0; struct option options[] = { OPT__ABBREV(&abbrev), OPT__VERBOSE(&verbose, N_("be verbose")), OPT_END() }; argc = parse_options(argc, argv, prefix, options, cherry_usage, 0); switch (argc) { case 3: limit = argv[2]; /* FALLTHROUGH */ case 2: head = argv[1]; /* FALLTHROUGH */ case 1: upstream = argv[0]; break; default: current_branch = branch_get(NULL); if (!current_branch || !current_branch->merge || !current_branch->merge[0] || !current_branch->merge[0]->dst) { fprintf(stderr, _("Could not find a tracked" " remote branch, please" " specify <upstream> manually.\n")); usage_with_options(cherry_usage, options); } upstream = current_branch->merge[0]->dst; } init_revisions(&revs, prefix); revs.max_parents = 1; if (add_pending_commit(head, &revs, 0)) die(_("Unknown commit %s"), head); if (add_pending_commit(upstream, &revs, UNINTERESTING)) die(_("Unknown commit %s"), upstream); /* Don't say anything if head and upstream are the same. */ if (revs.pending.nr == 2) { struct object_array_entry *o = revs.pending.objects; if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0) return 0; } get_patch_ids(&revs, &ids); if (limit && add_pending_commit(limit, &revs, UNINTERESTING)) die(_("Unknown commit %s"), limit); /* reverse the list of commits */ if (prepare_revision_walk(&revs)) die(_("revision walk setup failed")); while ((commit = get_revision(&revs)) != NULL) { commit_list_insert(commit, &list); } while (list) { char sign = '+'; commit = list->item; if (has_commit_patch_id(commit, &ids)) sign = '-'; print_commit(sign, commit, verbose, abbrev); list = list->next; } free_patch_ids(&ids); return 0; }
static void fill_tracking_info(struct strbuf *stat, const char *branch_name, int show_upstream_ref) { int ours, theirs; char *ref = NULL; struct branch *branch = branch_get(branch_name); struct strbuf fancy = STRBUF_INIT; int upstream_is_gone = 0; int added_decoration = 1; switch (stat_tracking_info(branch, &ours, &theirs)) { case 0: /* no base */ return; case -1: /* with "gone" base */ upstream_is_gone = 1; break; default: /* with base */ break; } if (show_upstream_ref) { ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0); if (want_color(branch_use_color)) strbuf_addf(&fancy, "%s%s%s", branch_get_color(BRANCH_COLOR_UPSTREAM), ref, branch_get_color(BRANCH_COLOR_RESET)); else strbuf_addstr(&fancy, ref); } if (upstream_is_gone) { if (show_upstream_ref) strbuf_addf(stat, _("[%s: gone]"), fancy.buf); else added_decoration = 0; } else if (!ours && !theirs) { if (show_upstream_ref) strbuf_addf(stat, _("[%s]"), fancy.buf); else added_decoration = 0; } else if (!ours) { if (show_upstream_ref) strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs); else strbuf_addf(stat, _("[behind %d]"), theirs); } else if (!theirs) { if (show_upstream_ref) strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours); else strbuf_addf(stat, _("[ahead %d]"), ours); } else { if (show_upstream_ref) strbuf_addf(stat, _("[%s: ahead %d, behind %d]"), fancy.buf, ours, theirs); else strbuf_addf(stat, _("[ahead %d, behind %d]"), ours, theirs); } strbuf_release(&fancy); if (added_decoration) strbuf_addch(stat, ' '); free(ref); }
static void wt_shortstatus_print_tracking(struct wt_status *s) { struct branch *branch; const char *header_color = color(WT_STATUS_HEADER, s); const char *branch_color_local = color(WT_STATUS_LOCAL_BRANCH, s); const char *branch_color_remote = color(WT_STATUS_REMOTE_BRANCH, s); const char *base; const char *branch_name; int num_ours, num_theirs; int upstream_is_gone = 0; color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## "); if (!s->branch) return; branch_name = s->branch; if (starts_with(branch_name, "refs/heads/")) branch_name += 11; else if (!strcmp(branch_name, "HEAD")) { branch_name = _("HEAD (no branch)"); branch_color_local = color(WT_STATUS_NOBRANCH, s); } branch = branch_get(s->branch + 11); if (s->is_initial) color_fprintf(s->fp, header_color, _("Initial commit on ")); color_fprintf(s->fp, branch_color_local, "%s", branch_name); if (stat_tracking_info(branch, &num_ours, &num_theirs, &base) < 0) { if (!base) { fputc(s->null_termination ? '\0' : '\n', s->fp); return; } upstream_is_gone = 1; } base = shorten_unambiguous_ref(base, 0); color_fprintf(s->fp, header_color, "..."); color_fprintf(s->fp, branch_color_remote, "%s", base); free((char *)base); if (!upstream_is_gone && !num_ours && !num_theirs) { fputc(s->null_termination ? '\0' : '\n', s->fp); return; } #define LABEL(string) (s->no_gettext ? (string) : _(string)) color_fprintf(s->fp, header_color, " ["); if (upstream_is_gone) { color_fprintf(s->fp, header_color, LABEL(N_("gone"))); } else if (!num_ours) { color_fprintf(s->fp, header_color, LABEL(N_("behind "))); color_fprintf(s->fp, branch_color_remote, "%d", num_theirs); } else if (!num_theirs) { color_fprintf(s->fp, header_color, LABEL(N_(("ahead ")))); color_fprintf(s->fp, branch_color_local, "%d", num_ours); } else { color_fprintf(s->fp, header_color, LABEL(N_(("ahead ")))); color_fprintf(s->fp, branch_color_local, "%d", num_ours); color_fprintf(s->fp, header_color, ", %s", LABEL(N_("behind "))); color_fprintf(s->fp, branch_color_remote, "%d", num_theirs); } color_fprintf(s->fp, header_color, "]"); fputc(s->null_termination ? '\0' : '\n', s->fp); }
static int do_push(const char *repo, int flags) { int i, errs; struct remote *remote = pushremote_get(repo); const char **url; int url_nr; if (!remote) { if (repo) die(_("bad repository '%s'"), repo); die(_("No configured push destination.\n" "Either specify the URL from the command-line or configure a remote repository using\n" "\n" " git remote add <name> <url>\n" "\n" "and then push using the remote name\n" "\n" " git push <name>\n")); } if (remote->mirror) flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE); if ((flags & TRANSPORT_PUSH_ALL) && refspec) { if (!strcmp(*refspec, "refs/tags/*")) return error(_("--all and --tags are incompatible")); return error(_("--all can't be combined with refspecs")); } if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) { if (!strcmp(*refspec, "refs/tags/*")) return error(_("--mirror and --tags are incompatible")); return error(_("--mirror can't be combined with refspecs")); } if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) == (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) { return error(_("--all and --mirror are incompatible")); } if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) { struct branch *branch = branch_get(NULL); /* Is there a publish branch */ if (branch && branch->pushremote_name && !strcmp(remote->name, branch->pushremote_name) && branch->push_name) { struct strbuf refspec = STRBUF_INIT; strbuf_addf(&refspec, "%s:%s", branch->name, branch->push_name); add_refspec(refspec.buf); } else if (remote->push_refspec_nr) { refspec = remote->push_refspec; refspec_nr = remote->push_refspec_nr; } else if (!(flags & TRANSPORT_PUSH_MIRROR)) setup_default_push_refspecs(remote); } errs = 0; url_nr = push_url_of_remote(remote, &url); if (url_nr) { for (i = 0; i < url_nr; i++) { struct transport *transport = transport_get(remote, url[i]); if (push_with_options(transport, flags)) errs++; } } else { struct transport *transport = transport_get(remote, NULL); if (push_with_options(transport, flags)) errs++; } return !!errs; }
static int update_local_ref(struct ref *ref, const char *remote, char *display) { struct commit *current = NULL, *updated; enum object_type type; struct branch *current_branch = branch_get(NULL); const char *pretty_ref = prettify_refname(ref->name); *display = 0; type = sha1_object_info(ref->new_sha1, NULL); if (type < 0) die("object %s not found", sha1_to_hex(ref->new_sha1)); if (!hashcmp(ref->old_sha1, ref->new_sha1)) { if (verbosity > 0) sprintf(display, "= %-*s %-*s -> %s", TRANSPORT_SUMMARY_WIDTH, "[up to date]", REFCOL_WIDTH, remote, pretty_ref); return 0; } if (current_branch && !strcmp(ref->name, current_branch->name) && !(update_head_ok || is_bare_repository()) && !is_null_sha1(ref->old_sha1)) { /* * If this is the head, and it's not okay to update * the head, and the old value of the head isn't empty... */ sprintf(display, "! %-*s %-*s -> %s (can't fetch in current branch)", TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, pretty_ref); return 1; } if (!is_null_sha1(ref->old_sha1) && !prefixcmp(ref->name, "refs/tags/")) { int r; r = s_update_ref("updating tag", ref, 0); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '-', TRANSPORT_SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } current = lookup_commit_reference_gently(ref->old_sha1, 1); updated = lookup_commit_reference_gently(ref->new_sha1, 1); if (!current || !updated) { const char *msg; const char *what; int r; if (!strncmp(ref->name, "refs/tags/", 10)) { msg = "storing tag"; what = "[new tag]"; } else { msg = "storing head"; what = "[new branch]"; } r = s_update_ref(msg, ref, 0); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', TRANSPORT_SUMMARY_WIDTH, what, REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } if (in_merge_bases(current, &updated, 1)) { char quickref[83]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, ".."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); r = s_update_ref("fast-forward", ref, 1); sprintf(display, "%c %-*s %-*s -> %s%s", r ? '!' : ' ', TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref, r ? " (unable to update local ref)" : ""); return r; } else if (force || ref->force) { char quickref[84]; int r; strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); strcat(quickref, "..."); strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV)); r = s_update_ref("forced-update", ref, 1); sprintf(display, "%c %-*s %-*s -> %s (%s)", r ? '!' : '+', TRANSPORT_SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref, r ? "unable to update local ref" : "forced update"); return r; } else { sprintf(display, "! %-*s %-*s -> %s (non-fast-forward)", TRANSPORT_SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote, pretty_ref); return 1; } }