static void find_non_local_tags(struct transport *transport, struct ref **head, struct ref ***tail) { struct path_list existing_refs = { NULL, 0, 0, 0 }; struct path_list new_refs = { NULL, 0, 0, 1 }; char *ref_name; int ref_name_len; const unsigned char *ref_sha1; const struct ref *tag_ref; struct ref *rm = NULL; const struct ref *ref; for_each_ref(add_existing, &existing_refs); for (ref = transport_get_remote_refs(transport); ref; ref = ref->next) { if (prefixcmp(ref->name, "refs/tags")) continue; ref_name = xstrdup(ref->name); ref_name_len = strlen(ref_name); ref_sha1 = ref->old_sha1; if (!strcmp(ref_name + ref_name_len - 3, "^{}")) { ref_name[ref_name_len - 3] = 0; tag_ref = transport_get_remote_refs(transport); while (tag_ref) { if (!strcmp(tag_ref->name, ref_name)) { ref_sha1 = tag_ref->old_sha1; break; } tag_ref = tag_ref->next; } } if (!path_list_has_path(&existing_refs, ref_name) && !path_list_has_path(&new_refs, ref_name) && (has_sha1_file(ref->old_sha1) || will_fetch(head, ref->old_sha1))) { path_list_insert(ref_name, &new_refs); rm = alloc_ref_from_str(ref_name); rm->peer_ref = alloc_ref_from_str(ref_name); hashcpy(rm->old_sha1, ref_sha1); **tail = rm; *tail = &rm->next; } free(ref_name); } path_list_clear(&existing_refs, 0); path_list_clear(&new_refs, 0); }
void shortlog_output(struct shortlog *log) { int i, j; if (log->sort_by_number) qsort(log->list.items, log->list.nr, sizeof(struct path_list_item), compare_by_number); for (i = 0; i < log->list.nr; i++) { struct path_list *onelines = log->list.items[i].util; if (log->summary) { printf("%6d\t%s\n", onelines->nr, log->list.items[i].path); } else { printf("%s (%d):\n", log->list.items[i].path, onelines->nr); for (j = onelines->nr - 1; j >= 0; j--) { const char *msg = onelines->items[j].path; if (log->wrap_lines) { int col = print_wrapped_text(msg, log->in1, log->in2, log->wrap); if (col != log->wrap) putchar('\n'); } else printf(" %s\n", msg); } putchar('\n'); } onelines->strdup_paths = 1; path_list_clear(onelines, 1); free(onelines); log->list.items[i].util = NULL; } log->list.strdup_paths = 1; path_list_clear(&log->list, 1); log->mailmap.strdup_paths = 1; path_list_clear(&log->mailmap, 1); }
static int split_maildir(const char *maildir, const char *dir, int nr_prec, int skip) { char file[PATH_MAX]; char name[PATH_MAX]; int ret = -1; int i; struct path_list list = {NULL, 0, 0, 1}; if (populate_maildir_list(&list, maildir) < 0) goto out; for (i = 0; i < list.nr; i++) { FILE *f; snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].path); f = fopen(file, "r"); if (!f) { error("cannot open mail %s (%s)", file, strerror(errno)); goto out; } if (fgets(buf, sizeof(buf), f) == NULL) { error("cannot read mail %s (%s)", file, strerror(errno)); goto out; } sprintf(name, "%s/%0*d", dir, nr_prec, ++skip); split_one(f, name, 1); fclose(f); } ret = skip; out: path_list_clear(&list, 1); return ret; }
static int process_renames(struct path_list *a_renames, struct path_list *b_renames, const char *a_branch, const char *b_branch) { int clean_merge = 1, i, j; struct path_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0}; const struct rename *sre; for (i = 0; i < a_renames->nr; i++) { sre = a_renames->items[i].util; path_list_insert(sre->pair->two->path, &a_by_dst)->util = sre->dst_entry; } for (i = 0; i < b_renames->nr; i++) { sre = b_renames->items[i].util; path_list_insert(sre->pair->two->path, &b_by_dst)->util = sre->dst_entry; } for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) { int compare; char *src; struct path_list *renames1, *renames2, *renames2Dst; struct rename *ren1 = NULL, *ren2 = NULL; const char *branch1, *branch2; const char *ren1_src, *ren1_dst; if (i >= a_renames->nr) { compare = 1; ren2 = b_renames->items[j++].util; } else if (j >= b_renames->nr) { compare = -1; ren1 = a_renames->items[i++].util; } else { compare = strcmp(a_renames->items[i].path, b_renames->items[j].path); if (compare <= 0) ren1 = a_renames->items[i++].util; if (compare >= 0) ren2 = b_renames->items[j++].util; } /* TODO: refactor, so that 1/2 are not needed */ if (ren1) { renames1 = a_renames; renames2 = b_renames; renames2Dst = &b_by_dst; branch1 = a_branch; branch2 = b_branch; } else { struct rename *tmp; renames1 = b_renames; renames2 = a_renames; renames2Dst = &a_by_dst; branch1 = b_branch; branch2 = a_branch; tmp = ren2; ren2 = ren1; ren1 = tmp; } src = ren1->pair->one->path; ren1->dst_entry->processed = 1; ren1->src_entry->processed = 1; if (ren1->processed) continue; ren1->processed = 1; ren1_src = ren1->pair->one->path; ren1_dst = ren1->pair->two->path; if (ren2) { const char *ren2_src = ren2->pair->one->path; const char *ren2_dst = ren2->pair->two->path; /* Renamed in 1 and renamed in 2 */ if (strcmp(ren1_src, ren2_src) != 0) die("ren1.src != ren2.src"); ren2->dst_entry->processed = 1; ren2->processed = 1; if (strcmp(ren1_dst, ren2_dst) != 0) { clean_merge = 0; output(1, "CONFLICT (rename/rename): " "Rename \"%s\"->\"%s\" in branch \"%s\" " "rename \"%s\"->\"%s\" in \"%s\"%s", src, ren1_dst, branch1, src, ren2_dst, branch2, index_only ? " (left unresolved)": ""); if (index_only) { remove_file_from_cache(src); update_file(0, ren1->pair->one->sha1, ren1->pair->one->mode, src); } conflict_rename_rename(ren1, branch1, ren2, branch2); } else { struct merge_file_info mfi; remove_file(1, ren1_src, 1); mfi = merge_file(ren1->pair->one, ren1->pair->two, ren2->pair->two, branch1, branch2); if (mfi.merge || !mfi.clean) output(1, "Renamed %s->%s", src, ren1_dst); if (mfi.merge) output(2, "Auto-merged %s", ren1_dst); if (!mfi.clean) { output(1, "CONFLICT (content): merge conflict in %s", ren1_dst); clean_merge = 0; if (!index_only) update_stages(ren1_dst, ren1->pair->one, ren1->pair->two, ren2->pair->two, 1 /* clear */); } update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } else { /* Renamed in 1, maybe changed in 2 */ struct path_list_item *item; /* we only use sha1 and mode of these */ struct diff_filespec src_other, dst_other; int try_merge, stage = a_renames == renames1 ? 3: 2; remove_file(1, ren1_src, index_only || stage == 3); hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha); src_other.mode = ren1->src_entry->stages[stage].mode; hashcpy(dst_other.sha1, ren1->dst_entry->stages[stage].sha); dst_other.mode = ren1->dst_entry->stages[stage].mode; try_merge = 0; if (path_list_has_path(¤t_directory_set, ren1_dst)) { clean_merge = 0; output(1, "CONFLICT (rename/directory): Renamed %s->%s in %s " " directory %s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); conflict_rename_dir(ren1, branch1); } else if (sha_eq(src_other.sha1, null_sha1)) { clean_merge = 0; output(1, "CONFLICT (rename/delete): Renamed %s->%s in %s " "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst); } else if (!sha_eq(dst_other.sha1, null_sha1)) { const char *new_path; clean_merge = 0; try_merge = 1; output(1, "CONFLICT (rename/add): Renamed %s->%s in %s. " "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); output(1, "Added as %s instead", new_path); update_file(0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = path_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; ren2->processed = 1; output(1, "CONFLICT (rename/rename): Renamed %s->%s in %s. " "Renamed %s->%s in %s", ren1_src, ren1_dst, branch1, ren2->pair->one->path, ren2->pair->two->path, branch2); conflict_rename_rename_2(ren1, branch1, ren2, branch2); } else try_merge = 1; if (try_merge) { struct diff_filespec *o, *a, *b; struct merge_file_info mfi; src_other.path = (char *)ren1_src; o = ren1->pair->one; if (a_renames == renames1) { a = ren1->pair->two; b = &src_other; } else { b = ren1->pair->two; a = &src_other; } mfi = merge_file(o, a, b, a_branch, b_branch); if (mfi.clean && sha_eq(mfi.sha, ren1->pair->two->sha1) && mfi.mode == ren1->pair->two->mode) /* * This messaged is part of * t6022 test. If you change * it update the test too. */ output(3, "Skipped %s (merged same as existing)", ren1_dst); else { if (mfi.merge || !mfi.clean) output(1, "Renamed %s => %s", ren1_src, ren1_dst); if (mfi.merge) output(2, "Auto-merged %s", ren1_dst); if (!mfi.clean) { output(1, "CONFLICT (rename/modify): Merge conflict in %s", ren1_dst); clean_merge = 0; if (!index_only) update_stages(ren1_dst, o, a, b, 1); } update_file(mfi.clean, mfi.sha, mfi.mode, ren1_dst); } } } } path_list_clear(&a_by_dst, 0); path_list_clear(&b_by_dst, 0); return clean_merge; }
int merge_trees(struct tree *head, struct tree *merge, struct tree *common, const char *branch1, const char *branch2, struct tree **result) { int code, clean; if (subtree_merge) { merge = shift_tree_object(head, merge); common = shift_tree_object(head, common); } if (sha_eq(common->object.sha1, merge->object.sha1)) { output(0, "Already uptodate!"); *result = head; return 1; } code = git_merge_trees(index_only, common, head, merge); if (code != 0) die("merging of trees %s and %s failed", sha1_to_hex(head->object.sha1), sha1_to_hex(merge->object.sha1)); if (unmerged_cache()) { struct path_list *entries, *re_head, *re_merge; int i; path_list_clear(¤t_file_set, 1); path_list_clear(¤t_directory_set, 1); get_files_dirs(head); get_files_dirs(merge); entries = get_unmerged(); re_head = get_renames(head, common, head, merge, entries); re_merge = get_renames(merge, common, head, merge, entries); clean = process_renames(re_head, re_merge, branch1, branch2); for (i = 0; i < entries->nr; i++) { const char *path = entries->items[i].path; struct stage_data *e = entries->items[i].util; if (!e->processed && !process_entry(path, e, branch1, branch2)) clean = 0; } path_list_clear(re_merge, 0); path_list_clear(re_head, 0); path_list_clear(entries, 1); } else clean = 1; if (index_only) *result = write_tree_from_memory(); return clean; }