Jgit源码阅览——文件差异比较就是比较index文件的差别

Jgit源码阅读——文件差异比较就是比较index文件的差别
Jgit源码阅览——文件差异比较就是比较index文件的差别 Jgit源码阅览——文件差异比较就是比较index文件的差别



git比较文件差异是根据当前的index文件进行差量比较的.

这些差量信息如:

added files     已经add进index的file,也就是在objects目录中存在备份的file
changed files   内容发生改变,而且在index和版本库中都存在记录的file
removed files   已经被移除的file
missing files   已经不存在的file
modified files  内容发生改变,而且受控目录和index都存在的file
conflicting files 与已经存在版本相冲突的file
untracked files 还没被add进index的file
files with assume-unchanged flag 这个,知道说一下


这个是IndexDiff类中比较当前workTree跟版本库中文件状态 最关键的部分

	/**
	 * Run the diff operation. Until this is called, all lists will be empty.
	 * <p>
	 * The operation may be aborted by the progress monitor. In that event it
	 * will report what was found before the cancel operation was detected.
	 * Callers should ignore the result if monitor.isCancelled() is true. If a
	 * progress monitor is not needed, callers should use {@link #diff()}
	 * instead. Progress reporting is crude and approximate and only intended
	 * for informing the user.
	 *
	 * @param monitor
	 *            for reporting progress, may be null
	 * @param estWorkTreeSize
	 *            number or estimated files in the working tree
	 * @param estIndexSize
	 *            number of estimated entries in the cache
	 * @param title
	 *
	 * @return if anything is different between index, tree, and workdir
	 * @throws IOException
	 */
	public boolean diff(final ProgressMonitor monitor, int estWorkTreeSize,
			int estIndexSize, final String title)
			throws IOException {
		dirCache = repository.readDirCache();

		TreeWalk treeWalk = new TreeWalk(repository);
		treeWalk.setRecursive(true);
		// add the trees (tree, dirchache, workdir)
		if (tree != null)
			treeWalk.addTree(tree);
		else
			treeWalk.addTree(new EmptyTreeIterator());
		treeWalk.addTree(new DirCacheIterator(dirCache));
		treeWalk.addTree(initialWorkingTreeIterator);
		Collection<TreeFilter> filters = new ArrayList<TreeFilter>(4);

		if (monitor != null) {
			// Get the maximum size of the work tree and index
			// and add some (quite arbitrary)
			if (estIndexSize == 0)
				estIndexSize = dirCache.getEntryCount();
			int total = Math.max(estIndexSize * 10 / 9,
					estWorkTreeSize * 10 / 9);
			monitor.beginTask(title, total);
			filters.add(new ProgressReportingFilter(monitor, total));
		}

		if (filter != null)
			filters.add(filter);
		filters.add(new SkipWorkTreeFilter(INDEX));
		indexDiffFilter = new IndexDiffFilter(INDEX, WORKDIR);
		filters.add(indexDiffFilter);
		treeWalk.setFilter(AndTreeFilter.create(filters));
		while (treeWalk.next()) {
			AbstractTreeIterator treeIterator = treeWalk.getTree(TREE,
					AbstractTreeIterator.class);
			DirCacheIterator dirCacheIterator = treeWalk.getTree(INDEX,
					DirCacheIterator.class);
			WorkingTreeIterator workingTreeIterator = treeWalk.getTree(WORKDIR,
					WorkingTreeIterator.class);

			if (dirCacheIterator != null) {
				final DirCacheEntry dirCacheEntry = dirCacheIterator
						.getDirCacheEntry();
				if (dirCacheEntry != null && dirCacheEntry.getStage() > 0) {
					conflicts.add(treeWalk.getPathString());
					continue;
				}
			}

			if (treeIterator != null) {
				if (dirCacheIterator != null) {
					if (!treeIterator.idEqual(dirCacheIterator)
							|| treeIterator.getEntryRawMode()
							!= dirCacheIterator.getEntryRawMode()) {
						// in repo, in index, content diff => changed
						changed.add(treeWalk.getPathString());
					}
				} else {
					// in repo, not in index => removed
					removed.add(treeWalk.getPathString());
					if (workingTreeIterator != null)
						untracked.add(treeWalk.getPathString());
				}
			} else {
				if (dirCacheIterator != null) {
					// not in repo, in index => added
					added.add(treeWalk.getPathString());
				} else {
					// not in repo, not in index => untracked
					if (workingTreeIterator != null
							&& !workingTreeIterator.isEntryIgnored()) {
						untracked.add(treeWalk.getPathString());
					}
				}
			}

			if (dirCacheIterator != null) {
				if (workingTreeIterator == null) {
					// in index, not in workdir => missing
					missing.add(treeWalk.getPathString());
				} else {
					if (workingTreeIterator.isModified(
							dirCacheIterator.getDirCacheEntry(), true)) {
						// in index, in workdir, content differs => modified
						modified.add(treeWalk.getPathString());
					}
				}
			}
		}

		// consume the remaining work
		if (monitor != null)
			monitor.endTask();

		ignored = indexDiffFilter.getIgnoredPaths();
		if (added.isEmpty() && changed.isEmpty() && removed.isEmpty()
				&& missing.isEmpty() && modified.isEmpty()
				&& untracked.isEmpty())
			return false;
		else
			return true;
	}





代码分析:
52行: 过滤器,以当前受控workTree为过滤点
55行:遍历受控目录中所有的文件.
66行:如果版本库中包含该entry,但dirCacheEntry.getStage()大于零, 被记录到版本库后,stage有四个值,如下
	/** The standard (fully merged) stage for an entry. */
	public static final int STAGE_0 = 0;

	/** The base tree revision for an entry. */
	public static final int STAGE_1 = 1;

	/** The first tree revision (usually called "ours"). */
	public static final int STAGE_2 = 2;

	/** The second tree revision (usually called "theirs"). */
	public static final int STAGE_3 = 3;
.
这个时候,在受控目录中的文件为冲突态.
78行:如果已经存在index和版本库中,这个文件内容又发生了改变,这个时候,这个文件是changes状态
82-84行:在版本库中,但是已经不在index状态了,是remove状态,

102行,:如果该文件在index中,但是在受控目录不见了,定义为missing状态,一般在eclipse的egit中可以看到这个状态




不一一分析,从此可以看到git在切换分支的时候如此之快,其实就是拿index出来比较,因为index已经索引了文件在objects的位置.














作者:http://414149609.iteye.com/admin/blogs/1668995