Exemplo n.º 1
0
static int get_stat_data(struct cache_entry *ce,
			 const unsigned char **sha1p,
			 unsigned int *modep,
			 int cached, int match_missing)
{
	const unsigned char *sha1 = ce->sha1;
	unsigned int mode = ce->ce_mode;

	if (!cached && !ce_uptodate(ce)) {
		int changed;
		struct stat st;
		changed = check_removed(ce, &st);
		if (changed < 0)
			return -1;
		else if (changed) {
			if (match_missing) {
				*sha1p = sha1;
				*modep = mode;
				return 0;
			}
			return -1;
		}
		changed = ce_match_stat(ce, &st, 0);
		if (changed) {
			mode = ce_mode_from_stat(ce, st.st_mode);
			sha1 = null_sha1;
		}
	}

	*sha1p = sha1;
	*modep = mode;
	return 0;
}
Exemplo n.º 2
0
void stage_updated_gitmodules(void)
{
	struct strbuf buf = STRBUF_INIT;
	struct stat st;
	int pos;
	struct cache_entry *ce;
	int namelen = strlen(".gitmodules");

	pos = cache_name_pos(".gitmodules", namelen);
	if (pos < 0) {
		warning(_("could not find .gitmodules in index"));
		return;
	}
	ce = active_cache[pos];
	ce->ce_flags = namelen;
	if (strbuf_read_file(&buf, ".gitmodules", 0) < 0)
		die(_("reading updated .gitmodules failed"));
	if (lstat(".gitmodules", &st) < 0)
		die_errno(_("unable to stat updated .gitmodules"));
	fill_stat_cache_info(ce, &st);
	ce->ce_mode = ce_mode_from_stat(ce, st.st_mode);
	if (remove_cache_entry_at(pos) < 0)
		die(_("unable to remove .gitmodules from index"));
	if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1))
		die(_("adding updated .gitmodules failed"));
	if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
		die(_("staging updated .gitmodules failed"));
}
Exemplo n.º 3
0
static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
{
	int option, size;
	struct cache_entry *ce;

	/* Was the old index entry already up-to-date? */
	if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
		return 0;

	size = cache_entry_size(len);
	ce = xcalloc(1, size);
	memcpy(ce->name, path, len);
	ce->ce_flags = create_ce_flags(0);
	ce->ce_namelen = len;
	fill_stat_cache_info(ce, st);
	ce->ce_mode = ce_mode_from_stat(old, st->st_mode);

	if (index_path(ce->sha1, path, st,
		       info_only ? 0 : HASH_WRITE_OBJECT)) {
		free(ce);
		return -1;
	}
	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
	if (add_cache_entry(ce, option))
		return error("%s: cannot add to the index - missing --add option?", path);
	return 0;
}
Exemplo n.º 4
0
static int get_stat_data(const struct cache_entry *ce,
			 const struct object_id **oidp,
			 unsigned int *modep,
			 int cached, int match_missing,
			 unsigned *dirty_submodule, struct diff_options *diffopt)
{
	const struct object_id *oid = &ce->oid;
	unsigned int mode = ce->ce_mode;

	if (!cached && !ce_uptodate(ce)) {
		int changed;
		struct stat st;
		changed = check_removed(ce, &st);
		if (changed < 0)
			return -1;
		else if (changed) {
			if (match_missing) {
				*oidp = oid;
				*modep = mode;
				return 0;
			}
			return -1;
		}
		changed = match_stat_with_submodule(diffopt, ce, &st,
						    0, dirty_submodule);
		if (changed) {
			mode = ce_mode_from_stat(ce, st.st_mode);
			oid = &null_oid;
		}
	}

	*oidp = oid;
	*modep = mode;
	return 0;
}
Exemplo n.º 5
0
static int get_stat_data(struct cache_entry *ce,
                         const unsigned char **sha1p,
                         unsigned int *modep,
                         int cached, int match_missing,
                         unsigned *dirty_submodule, struct diff_options *diffopt)
{
    const unsigned char *sha1 = ce->sha1;
    unsigned int mode = ce->ce_mode;

    if (!cached && !ce_uptodate(ce)) {
        int changed;
        struct stat st;
        changed = check_removed(ce, &st);
        if (changed < 0)
            return -1;
        else if (changed) {
            if (match_missing) {
                *sha1p = sha1;
                *modep = mode;
                return 0;
            }
            return -1;
        }
        changed = ce_match_stat(ce, &st, 0);
        if (S_ISGITLINK(ce->ce_mode)
                && !DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES)
                && (!changed || (diffopt->output_format & DIFF_FORMAT_PATCH))
                && is_submodule_modified(ce->name)) {
            changed = 1;
            *dirty_submodule = 1;
        }
        if (changed) {
            mode = ce_mode_from_stat(ce, st.st_mode);
            sha1 = null_sha1;
        }
    }

    *sha1p = sha1;
    *modep = mode;
    return 0;
}
Exemplo n.º 6
0
int run_diff_files(struct rev_info *revs, unsigned int option)
{
	int entries, i;
	int diff_unmerged_stage = revs->max_count;
	int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
			      ? CE_MATCH_RACY_IS_DIRTY : 0);

	diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");

	if (diff_unmerged_stage < 0)
		diff_unmerged_stage = 2;
	entries = active_nr;
	for (i = 0; i < entries; i++) {
		struct stat st;
		unsigned int oldmode, newmode;
		struct cache_entry *ce = active_cache[i];
		int changed;

		if (DIFF_OPT_TST(&revs->diffopt, QUIET) &&
			DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
			break;

		if (!ce_path_match(ce, revs->prune_data))
			continue;

		if (ce_stage(ce)) {
			struct combine_diff_path *dpath;
			int num_compare_stages = 0;
			size_t path_len;

			path_len = ce_namelen(ce);

			dpath = xmalloc(combine_diff_path_size(5, path_len));
			dpath->path = (char *) &(dpath->parent[5]);

			dpath->next = NULL;
			dpath->len = path_len;
			memcpy(dpath->path, ce->name, path_len);
			dpath->path[path_len] = '\0';
			hashclr(dpath->sha1);
			memset(&(dpath->parent[0]), 0,
			       sizeof(struct combine_diff_parent)*5);

			changed = check_removed(ce, &st);
			if (!changed)
				dpath->mode = ce_mode_from_stat(ce, st.st_mode);
			else {
				if (changed < 0) {
					perror(ce->name);
					continue;
				}
				if (silent_on_removed)
					continue;
			}

			while (i < entries) {
				struct cache_entry *nce = active_cache[i];
				int stage;

				if (strcmp(ce->name, nce->name))
					break;

				/* Stage #2 (ours) is the first parent,
				 * stage #3 (theirs) is the second.
				 */
				stage = ce_stage(nce);
				if (2 <= stage) {
					int mode = nce->ce_mode;
					num_compare_stages++;
					hashcpy(dpath->parent[stage-2].sha1, nce->sha1);
					dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
					dpath->parent[stage-2].status =
						DIFF_STATUS_MODIFIED;
				}

				/* diff against the proper unmerged stage */
				if (stage == diff_unmerged_stage)
					ce = nce;
				i++;
			}
			/*
			 * Compensate for loop update
			 */
			i--;

			if (revs->combine_merges && num_compare_stages == 2) {
				show_combined_diff(dpath, 2,
						   revs->dense_combined_merges,
						   revs);
				free(dpath);
				continue;
			}
			free(dpath);
			dpath = NULL;

			/*
			 * Show the diff for the 'ce' if we found the one
			 * from the desired stage.
			 */
			diff_unmerge(&revs->diffopt, ce->name, 0, null_sha1);
			if (ce_stage(ce) != diff_unmerged_stage)
				continue;
		}

		if (ce_uptodate(ce))
			continue;

		changed = check_removed(ce, &st);
		if (changed) {
			if (changed < 0) {
				perror(ce->name);
				continue;
			}
			if (silent_on_removed)
				continue;
			diff_addremove(&revs->diffopt, '-', ce->ce_mode,
				       ce->sha1, ce->name);
			continue;
		}
		changed = ce_match_stat(ce, &st, ce_option);
		if (!changed) {
			ce_mark_uptodate(ce);
			if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
				continue;
		}
		oldmode = ce->ce_mode;
		newmode = ce_mode_from_stat(ce, st.st_mode);
		diff_change(&revs->diffopt, oldmode, newmode,
			    ce->sha1, (changed ? null_sha1 : ce->sha1),
			    ce->name);

	}
	diffcore_std(&revs->diffopt);
	diff_flush(&revs->diffopt);
	return 0;
}
Exemplo n.º 7
0
Arquivo: diff-lib.c Projeto: 0369/git
int run_diff_files(struct rev_info *revs, unsigned int option)
{
	int entries, i;
	int diff_unmerged_stage = revs->max_count;
	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
			      ? CE_MATCH_RACY_IS_DIRTY : 0);

	diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");

	if (diff_unmerged_stage < 0)
		diff_unmerged_stage = 2;
	entries = active_nr;
	for (i = 0; i < entries; i++) {
		unsigned int oldmode, newmode;
		struct cache_entry *ce = active_cache[i];
		int changed;
		unsigned dirty_submodule = 0;
		const unsigned char *old_sha1, *new_sha1;

		if (diff_can_quit_early(&revs->diffopt))
			break;

		if (!ce_path_match(ce, &revs->prune_data, NULL))
			continue;

		if (ce_stage(ce)) {
			struct combine_diff_path *dpath;
			struct diff_filepair *pair;
			unsigned int wt_mode = 0;
			int num_compare_stages = 0;
			size_t path_len;
			struct stat st;

			path_len = ce_namelen(ce);

			dpath = xmalloc(combine_diff_path_size(5, path_len));
			dpath->path = (char *) &(dpath->parent[5]);

			dpath->next = NULL;
			memcpy(dpath->path, ce->name, path_len);
			dpath->path[path_len] = '\0';
			oidclr(&dpath->oid);
			memset(&(dpath->parent[0]), 0,
			       sizeof(struct combine_diff_parent)*5);

			changed = check_removed(ce, &st);
			if (!changed)
				wt_mode = ce_mode_from_stat(ce, st.st_mode);
			else {
				if (changed < 0) {
					perror(ce->name);
					continue;
				}
				wt_mode = 0;
			}
			dpath->mode = wt_mode;

			while (i < entries) {
				struct cache_entry *nce = active_cache[i];
				int stage;

				if (strcmp(ce->name, nce->name))
					break;

				/* Stage #2 (ours) is the first parent,
				 * stage #3 (theirs) is the second.
				 */
				stage = ce_stage(nce);
				if (2 <= stage) {
					int mode = nce->ce_mode;
					num_compare_stages++;
					hashcpy(dpath->parent[stage-2].oid.hash, nce->sha1);
					dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
					dpath->parent[stage-2].status =
						DIFF_STATUS_MODIFIED;
				}

				/* diff against the proper unmerged stage */
				if (stage == diff_unmerged_stage)
					ce = nce;
				i++;
			}
			/*
			 * Compensate for loop update
			 */
			i--;

			if (revs->combine_merges && num_compare_stages == 2) {
				show_combined_diff(dpath, 2,
						   revs->dense_combined_merges,
						   revs);
				free(dpath);
				continue;
			}
			free(dpath);
			dpath = NULL;

			/*
			 * Show the diff for the 'ce' if we found the one
			 * from the desired stage.
			 */
			pair = diff_unmerge(&revs->diffopt, ce->name);
			if (wt_mode)
				pair->two->mode = wt_mode;
			if (ce_stage(ce) != diff_unmerged_stage)
				continue;
		}

		if (ce_uptodate(ce) || ce_skip_worktree(ce))
			continue;

		/* If CE_VALID is set, don't look at workdir for file removal */
		if (ce->ce_flags & CE_VALID) {
			changed = 0;
			newmode = ce->ce_mode;
		} else {
			struct stat st;

			changed = check_removed(ce, &st);
			if (changed) {
				if (changed < 0) {
					perror(ce->name);
					continue;
				}
				diff_addremove(&revs->diffopt, '-', ce->ce_mode,
					       ce->sha1, !is_null_sha1(ce->sha1),
					       ce->name, 0);
				continue;
			}

			changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
							    ce_option, &dirty_submodule);
			newmode = ce_mode_from_stat(ce, st.st_mode);
		}

		if (!changed && !dirty_submodule) {
			ce_mark_uptodate(ce);
			if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
				continue;
		}
		oldmode = ce->ce_mode;
		old_sha1 = ce->sha1;
		new_sha1 = changed ? null_sha1 : ce->sha1;
		diff_change(&revs->diffopt, oldmode, newmode,
			    old_sha1, new_sha1,
			    !is_null_sha1(old_sha1),
			    !is_null_sha1(new_sha1),
			    ce->name, 0, dirty_submodule);

	}
	diffcore_std(&revs->diffopt);
	diff_flush(&revs->diffopt);
	return 0;
}
Exemplo n.º 8
0
Arquivo: difftool.c Projeto: dscho/git
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
                        int argc, const char **argv)
{
    char tmpdir[PATH_MAX];
    struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
    struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;
    struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
    struct strbuf wtdir = STRBUF_INIT;
    size_t ldir_len, rdir_len, wtdir_len;
    struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1);
    const char *workdir, *tmp;
    int ret = 0, i;
    FILE *fp;
    struct hashmap working_tree_dups, submodules, symlinks2;
    struct hashmap_iter iter;
    struct pair_entry *entry;
    enum object_type type;
    unsigned long size;
    struct index_state wtindex;
    struct checkout lstate, rstate;
    int rc, flags = RUN_GIT_CMD, err = 0;
    struct child_process child = CHILD_PROCESS_INIT;
    const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL };
    struct hashmap wt_modified, tmp_modified;
    int indices_loaded = 0;

    workdir = get_git_work_tree();

    /* Setup temp directories */
    tmp = getenv("TMPDIR");
    xsnprintf(tmpdir, sizeof(tmpdir), "%s/git-difftool.XXXXXX", tmp ? tmp : "/tmp");
    if (!mkdtemp(tmpdir))
        return error("could not create '%s'", tmpdir);
    strbuf_addf(&ldir, "%s/left/", tmpdir);
    strbuf_addf(&rdir, "%s/right/", tmpdir);
    strbuf_addstr(&wtdir, workdir);
    if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1]))
        strbuf_addch(&wtdir, '/');
    mkdir(ldir.buf, 0700);
    mkdir(rdir.buf, 0700);

    memset(&wtindex, 0, sizeof(wtindex));

    memset(&lstate, 0, sizeof(lstate));
    lstate.base_dir = ldir.buf;
    lstate.base_dir_len = ldir.len;
    lstate.force = 1;
    memset(&rstate, 0, sizeof(rstate));
    rstate.base_dir = rdir.buf;
    rstate.base_dir_len = rdir.len;
    rstate.force = 1;

    ldir_len = ldir.len;
    rdir_len = rdir.len;
    wtdir_len = wtdir.len;

    hashmap_init(&working_tree_dups,
                 (hashmap_cmp_fn)working_tree_entry_cmp, 0);
    hashmap_init(&submodules, (hashmap_cmp_fn)pair_cmp, 0);
    hashmap_init(&symlinks2, (hashmap_cmp_fn)pair_cmp, 0);

    child.no_stdin = 1;
    child.git_cmd = 1;
    child.use_shell = 0;
    child.clean_on_exit = 1;
    child.dir = prefix;
    child.out = -1;
    argv_array_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
                     NULL);
    for (i = 0; i < argc; i++)
        argv_array_push(&child.args, argv[i]);
    if (start_command(&child))
        die("could not obtain raw diff");
    fp = xfdopen(child.out, "r");

    /* Build index info for left and right sides of the diff */
    i = 0;
    while (!strbuf_getline_nul(&info, fp)) {
        int lmode, rmode;
        struct object_id loid, roid;
        char status;
        const char *src_path, *dst_path;
        size_t src_path_len, dst_path_len;

        if (starts_with(info.buf, "::"))
            die(N_("combined diff formats('-c' and '--cc') are "
                   "not supported in\n"
                   "directory diff mode('-d' and '--dir-diff')."));

        if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid,
                             &status))
            break;
        if (strbuf_getline_nul(&lpath, fp))
            break;
        src_path = lpath.buf;
        src_path_len = lpath.len;

        i++;
        if (status != 'C' && status != 'R') {
            dst_path = src_path;
            dst_path_len = src_path_len;
        } else {
            if (strbuf_getline_nul(&rpath, fp))
                break;
            dst_path = rpath.buf;
            dst_path_len = rpath.len;
        }

        if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) {
            strbuf_reset(&buf);
            strbuf_addf(&buf, "Subproject commit %s",
                        oid_to_hex(&loid));
            add_left_or_right(&submodules, src_path, buf.buf, 0);
            strbuf_reset(&buf);
            strbuf_addf(&buf, "Subproject commit %s",
                        oid_to_hex(&roid));
            if (!oidcmp(&loid, &roid))
                strbuf_addstr(&buf, "-dirty");
            add_left_or_right(&submodules, dst_path, buf.buf, 1);
            continue;
        }

        if (S_ISLNK(lmode)) {
            char *content = read_sha1_file(loid.hash, &type, &size);
            add_left_or_right(&symlinks2, src_path, content, 0);
            free(content);
        }

        if (S_ISLNK(rmode)) {
            char *content = read_sha1_file(roid.hash, &type, &size);
            add_left_or_right(&symlinks2, dst_path, content, 1);
            free(content);
        }

        if (lmode && status != 'C') {
            ce->ce_mode = lmode;
            oidcpy(&ce->oid, &loid);
            strcpy(ce->name, src_path);
            ce->ce_namelen = src_path_len;
            if (checkout_entry(ce, &lstate, NULL))
                return error("could not write '%s'", src_path);
        }

        if (rmode) {
            struct working_tree_entry *entry;

            /* Avoid duplicate working_tree entries */
            FLEX_ALLOC_STR(entry, path, dst_path);
            hashmap_entry_init(entry, strhash(dst_path));
            if (hashmap_get(&working_tree_dups, entry, NULL)) {
                free(entry);
                continue;
            }
            hashmap_add(&working_tree_dups, entry);

            if (!use_wt_file(workdir, dst_path, &roid)) {
                ce->ce_mode = rmode;
                oidcpy(&ce->oid, &roid);
                strcpy(ce->name, dst_path);
                ce->ce_namelen = dst_path_len;
                if (checkout_entry(ce, &rstate, NULL))
                    return error("could not write '%s'",
                                 dst_path);
            } else if (!is_null_oid(&roid)) {
                /*
                 * Changes in the working tree need special
                 * treatment since they are not part of the
                 * index.
                 */
                struct cache_entry *ce2 =
                    make_cache_entry(rmode, roid.hash,
                                     dst_path, 0, 0);
                ce_mode_from_stat(ce2, rmode);

                add_index_entry(&wtindex, ce2,
                                ADD_CACHE_JUST_APPEND);

                add_path(&wtdir, wtdir_len, dst_path);
                add_path(&rdir, rdir_len, dst_path);
                if (ensure_leading_directories(rdir.buf))
                    return error("could not create "
                                 "directory for '%s'",
                                 dst_path);
                if (symlinks) {
                    if (symlink(wtdir.buf, rdir.buf)) {
                        ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf);
                        goto finish;
                    }
                } else {
                    struct stat st;
                    if (stat(wtdir.buf, &st))
                        st.st_mode = 0644;
                    if (copy_file(rdir.buf, wtdir.buf,
                                  st.st_mode)) {
                        ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf);
                        goto finish;
                    }
                }
            }
        }
    }

    if (finish_command(&child)) {
        ret = error("error occurred running diff --raw");
        goto finish;
    }

    if (!i)
        return 0;

    /*
     * Changes to submodules require special treatment.This loop writes a
     * temporary file to both the left and right directories to show the
     * change in the recorded SHA1 for the submodule.
     */
    hashmap_iter_init(&submodules, &iter);
    while ((entry = hashmap_iter_next(&iter))) {
        if (*entry->left) {
            add_path(&ldir, ldir_len, entry->path);
            ensure_leading_directories(ldir.buf);
            write_file(ldir.buf, "%s", entry->left);
        }
        if (*entry->right) {
            add_path(&rdir, rdir_len, entry->path);
            ensure_leading_directories(rdir.buf);
            write_file(rdir.buf, "%s", entry->right);
        }
    }

    /*
     * Symbolic links require special treatment.The standard "git diff"
     * shows only the link itself, not the contents of the link target.
     * This loop replicates that behavior.
     */
    hashmap_iter_init(&symlinks2, &iter);
    while ((entry = hashmap_iter_next(&iter))) {
        if (*entry->left) {
            add_path(&ldir, ldir_len, entry->path);
            ensure_leading_directories(ldir.buf);
            write_file(ldir.buf, "%s", entry->left);
        }
        if (*entry->right) {
            add_path(&rdir, rdir_len, entry->path);
            ensure_leading_directories(rdir.buf);
            write_file(rdir.buf, "%s", entry->right);
        }
    }

    strbuf_release(&buf);

    strbuf_setlen(&ldir, ldir_len);
    helper_argv[1] = ldir.buf;
    strbuf_setlen(&rdir, rdir_len);
    helper_argv[2] = rdir.buf;

    if (extcmd) {
        helper_argv[0] = extcmd;
        flags = 0;
    } else
        setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1);
    rc = run_command_v_opt(helper_argv, flags);

    /*
     * If the diff includes working copy files and those
     * files were modified during the diff, then the changes
     * should be copied back to the working tree.
     * Do not copy back files when symlinks are used and the
     * external tool did not replace the original link with a file.
     *
     * These hashes are loaded lazily since they aren't needed
     * in the common case of --symlinks and the difftool updating
     * files through the symlink.
     */
    hashmap_init(&wt_modified, (hashmap_cmp_fn)path_entry_cmp,
                 wtindex.cache_nr);
    hashmap_init(&tmp_modified, (hashmap_cmp_fn)path_entry_cmp,
                 wtindex.cache_nr);

    for (i = 0; i < wtindex.cache_nr; i++) {
        struct hashmap_entry dummy;
        const char *name = wtindex.cache[i]->name;
        struct stat st;

        add_path(&rdir, rdir_len, name);
        if (lstat(rdir.buf, &st))
            continue;

        if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode))
            continue;

        if (!indices_loaded) {
            static struct lock_file lock;
            strbuf_reset(&buf);
            strbuf_addf(&buf, "%s/wtindex", tmpdir);
            if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
                    write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
                ret = error("could not write %s", buf.buf);
                rollback_lock_file(&lock);
                goto finish;
            }
            changed_files(&wt_modified, buf.buf, workdir);
            strbuf_setlen(&rdir, rdir_len);
            changed_files(&tmp_modified, buf.buf, rdir.buf);
            add_path(&rdir, rdir_len, name);
            indices_loaded = 1;
        }

        hashmap_entry_init(&dummy, strhash(name));
        if (hashmap_get(&tmp_modified, &dummy, name)) {
            add_path(&wtdir, wtdir_len, name);
            if (hashmap_get(&wt_modified, &dummy, name)) {
                warning(_("both files modified: '%s' and '%s'."),
                        wtdir.buf, rdir.buf);
                warning(_("working tree file has been left."));
                warning("");
                err = 1;
            } else if (unlink(wtdir.buf) ||
                       copy_file(wtdir.buf, rdir.buf, st.st_mode))
                warning_errno(_("could not copy '%s' to '%s'"),
                              rdir.buf, wtdir.buf);
        }
    }

    if (err) {
        warning(_("temporary files exist in '%s'."), tmpdir);
        warning(_("you may want to cleanup or recover these."));
        exit(1);
    } else
        exit_cleanup(tmpdir, rc);

finish:
    free(ce);
    strbuf_release(&ldir);
    strbuf_release(&rdir);
    strbuf_release(&wtdir);
    strbuf_release(&buf);

    return ret;
}
Exemplo n.º 9
0
int run_diff_files(struct rev_info *revs, unsigned int option)
{
	int entries, i;
	int diff_unmerged_stage = revs->max_count;
	unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
			      ? CE_MATCH_RACY_IS_DIRTY : 0);
	uint64_t start = getnanotime();
	struct index_state *istate = revs->diffopt.repo->index;

	diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");

	if (diff_unmerged_stage < 0)
		diff_unmerged_stage = 2;
	entries = istate->cache_nr;
	for (i = 0; i < entries; i++) {
		unsigned int oldmode, newmode;
		struct cache_entry *ce = istate->cache[i];
		int changed;
		unsigned dirty_submodule = 0;
		const struct object_id *old_oid, *new_oid;

		if (diff_can_quit_early(&revs->diffopt))
			break;

		if (!ce_path_match(istate, ce, &revs->prune_data, NULL))
			continue;

		if (ce_stage(ce)) {
			struct combine_diff_path *dpath;
			struct diff_filepair *pair;
			unsigned int wt_mode = 0;
			int num_compare_stages = 0;
			size_t path_len;
			struct stat st;

			path_len = ce_namelen(ce);

			dpath = xmalloc(combine_diff_path_size(5, path_len));
			dpath->path = (char *) &(dpath->parent[5]);

			dpath->next = NULL;
			memcpy(dpath->path, ce->name, path_len);
			dpath->path[path_len] = '\0';
			oidclr(&dpath->oid);
			memset(&(dpath->parent[0]), 0,
			       sizeof(struct combine_diff_parent)*5);

			changed = check_removed(ce, &st);
			if (!changed)
				wt_mode = ce_mode_from_stat(ce, st.st_mode);
			else {
				if (changed < 0) {
					perror(ce->name);
					continue;
				}
				wt_mode = 0;
			}
			dpath->mode = wt_mode;

			while (i < entries) {
				struct cache_entry *nce = istate->cache[i];
				int stage;

				if (strcmp(ce->name, nce->name))
					break;

				/* Stage #2 (ours) is the first parent,
				 * stage #3 (theirs) is the second.
				 */
				stage = ce_stage(nce);
				if (2 <= stage) {
					int mode = nce->ce_mode;
					num_compare_stages++;
					oidcpy(&dpath->parent[stage - 2].oid,
					       &nce->oid);
					dpath->parent[stage-2].mode = ce_mode_from_stat(nce, mode);
					dpath->parent[stage-2].status =
						DIFF_STATUS_MODIFIED;
				}

				/* diff against the proper unmerged stage */
				if (stage == diff_unmerged_stage)
					ce = nce;
				i++;
			}
			/*
			 * Compensate for loop update
			 */
			i--;

			if (revs->combine_merges && num_compare_stages == 2) {
				show_combined_diff(dpath, 2,
						   revs->dense_combined_merges,
						   revs);
				free(dpath);
				continue;
			}
			FREE_AND_NULL(dpath);

			/*
			 * Show the diff for the 'ce' if we found the one
			 * from the desired stage.
			 */
			pair = diff_unmerge(&revs->diffopt, ce->name);
			if (wt_mode)
				pair->two->mode = wt_mode;
			if (ce_stage(ce) != diff_unmerged_stage)
				continue;
		}

		if (ce_uptodate(ce) || ce_skip_worktree(ce))
			continue;

		/* If CE_VALID is set, don't look at workdir for file removal */
		if (ce->ce_flags & CE_VALID) {
			changed = 0;
			newmode = ce->ce_mode;
		} else {
			struct stat st;

			changed = check_removed(ce, &st);
			if (changed) {
				if (changed < 0) {
					perror(ce->name);
					continue;
				}
				diff_addremove(&revs->diffopt, '-', ce->ce_mode,
					       &ce->oid,
					       !is_null_oid(&ce->oid),
					       ce->name, 0);
				continue;
			} else if (revs->diffopt.ita_invisible_in_index &&
				   ce_intent_to_add(ce)) {
				diff_addremove(&revs->diffopt, '+', ce->ce_mode,
					       the_hash_algo->empty_tree, 0,
					       ce->name, 0);
				continue;
			}

			changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
							    ce_option, &dirty_submodule);
			newmode = ce_mode_from_stat(ce, st.st_mode);
		}

		if (!changed && !dirty_submodule) {
			ce_mark_uptodate(ce);
			mark_fsmonitor_valid(ce);
			if (!revs->diffopt.flags.find_copies_harder)
				continue;
		}
		oldmode = ce->ce_mode;
		old_oid = &ce->oid;
		new_oid = changed ? &null_oid : &ce->oid;
		diff_change(&revs->diffopt, oldmode, newmode,
			    old_oid, new_oid,
			    !is_null_oid(old_oid),
			    !is_null_oid(new_oid),
			    ce->name, 0, dirty_submodule);

	}
	diffcore_std(&revs->diffopt);
	diff_flush(&revs->diffopt);
	trace_performance_since(start, "diff-files");
	return 0;
}