private void ProcessTree(RevObject obj) { try { _treeWalk.reset(obj); while (_treeWalk.next()) { FileMode mode = _treeWalk.getFileMode(0); int sType = (int)mode.ObjectType; switch (sType) { case Constants.OBJ_BLOB: case Constants.OBJ_TREE: _treeWalk.getObjectId(_idBuffer, 0); Needs(_revWalk.lookupAny(_idBuffer, sType)); continue; default: if (FileMode.GitLink.Equals(sType)) { continue; } _treeWalk.getObjectId(_idBuffer, 0); throw new CorruptObjectException("Invalid mode " + mode.ObjectType + " for " + _idBuffer.Name + " " + _treeWalk.getPathString() + " in " + obj.getId().Name + "."); } } } catch (IOException ioe) { throw new TransportException("Cannot Read tree " + obj.Name, ioe); } obj.add(COMPLETE); }
/// <summary> /// Recursively add an entire tree into this builder. /// <para /> /// If pathPrefix is "a/b" and the tree contains file "c" then the resulting /// DirCacheEntry will have the path "a/b/c". /// <para /> /// All entries are inserted at stage 0, therefore assuming that the /// application will not insert any other paths with the same pathPrefix. /// </summary> /// <param name="pathPrefix"> /// UTF-8 encoded prefix to mount the tree's entries at. If the /// path does not end with '/' one will be automatically inserted /// as necessary. /// </param> /// <param name="stage">Stage of the entries when adding them.</param> /// <param name="db"> /// Repository the tree(s) will be read from during recursive /// traversal. This must be the same repository that the resulting /// <see cref="DirCache"/> would be written out to (or used in) otherwise /// the caller is simply asking for deferred MissingObjectExceptions. /// </param> /// <param name="tree"> /// The tree to recursively add. This tree's contents will appear /// under <paramref name="pathPrefix"/>. The ObjectId must be that of a /// tree; the caller is responsible for dereferencing a tag or /// commit (if necessary). /// </param> /// <exception cref="IOException"> /// A tree cannot be read to iterate through its entries. /// </exception> public void addTree(byte[] pathPrefix, int stage, Repository db, AnyObjectId tree) { var tw = new TreeWalk.TreeWalk(db); tw.reset(); var curs = new WindowCursor(); try { tw.addTree(new CanonicalTreeParser(pathPrefix, db, tree.ToObjectId(), curs)); } finally { curs.Release(); } tw.Recursive = true; if (!tw.next()) { return; } DirCacheEntry newEntry = ToEntry(stage, tw); BeforeAdd(newEntry); FastAdd(newEntry); while (tw.next()) { FastAdd(ToEntry(stage, tw)); } }
public override bool include(RevWalk walker, RevCommit c) { // Reset the tree filter to scan this commit and parents. // RevCommit[] pList = c.Parents; int nParents = pList.Length; TreeWalk.TreeWalk tw = _pathFilter; var trees = new ObjectId[nParents + 1]; for (int i = 0; i < nParents; i++) { RevCommit p = c.Parents[i]; if ((p.Flags & Parsed) == 0) { p.parseHeaders(walker); } trees[i] = p.Tree; } trees[nParents] = c.Tree; tw.reset(trees); if (nParents == 1) { // We have exactly one parent. This is a very common case. // int chgs = 0, adds = 0; while (tw.next()) { chgs++; if (tw.getRawMode(0) == 0 && tw.getRawMode(1) != 0) { adds++; } else { break; // no point in looking at this further. } } if (chgs == 0) { // No changes, so our tree is effectively the same as // our parent tree. We pass the buck to our parent. // c.Flags |= Rewrite; return(false); } // We have interesting items, but neither of the special // cases denoted above. // return(true); } if (nParents == 0) { // We have no parents to compare against. Consider us to be // Rewrite only if we have no paths matching our filter. // if (tw.next()) { return(true); } c.Flags |= Rewrite; return(false); } // We are a merge commit. We can only be Rewrite if we are same // to _all_ parents. We may also be able to eliminate a parent if // it does not contribute changes to us. Such a parent may be an // uninteresting side branch. // var chgs_ = new int[nParents]; var adds_ = new int[nParents]; while (tw.next()) { int myMode = tw.getRawMode(nParents); for (int i = 0; i < nParents; i++) { int pMode = tw.getRawMode(i); if (myMode == pMode && tw.idEqual(i, nParents)) { continue; } chgs_[i]++; if (pMode == 0 && myMode != 0) { adds_[i]++; } } } bool same = false; bool diff = false; for (int i = 0; i < nParents; i++) { if (chgs_[i] == 0) { // No changes, so our tree is effectively the same as // this parent tree. We pass the buck to only this one // parent commit. // RevCommit p = pList[i]; if ((p.Flags & Uninteresting) != 0) { // This parent was marked as not interesting by the // application. We should look for another parent // that is interesting. // same = true; continue; } c.Flags |= Rewrite; c.Parents = new[] { p }; return(false); } if (chgs_[i] == adds_[i]) { // All of the differences from this parent were because we // added files that they did not have. This parent is our // "empty tree root" and thus their history is not relevant. // Cut our grandparents to be an empty list. // pList[i].Parents = RevCommit.NoParents; } // We have an interesting difference relative to this parent. // diff = true; } if (diff && !same) { // We did not abort above, so we are different in at least one // way from all of our parents. We have to take the blame for // that difference. // return(true); } // We are the same as all of our parents. We must keep them // as they are and allow those parents to flow into pending // for further scanning. // c.Flags |= Rewrite; return(false); }
/** * Recursively add an entire tree into this builder. * <p> * If pathPrefix is "a/b" and the tree contains file "c" then the resulting * DirCacheEntry will have the path "a/b/c". * <p> * All entries are inserted at stage 0, therefore assuming that the * application will not insert any other paths with the same pathPrefix. * * @param pathPrefix * UTF-8 encoded prefix to mount the tree's entries at. If the * path does not end with '/' one will be automatically inserted * as necessary. * @param stage * stage of the entries when adding them. * @param db * repository the tree(s) will be read from during recursive * traversal. This must be the same repository that the resulting * DirCache would be written out to (or used in) otherwise the * caller is simply asking for deferred MissingObjectExceptions. * @param tree * the tree to recursively add. This tree's contents will appear * under <code>pathPrefix</code>. The ObjectId must be that of a * tree; the caller is responsible for dereferencing a tag or * commit (if necessary). * @throws IOException * a tree cannot be read to iterate through its entries. */ public void addTree(byte[] pathPrefix, int stage, Repository db, AnyObjectId tree) { var tw = new TreeWalk.TreeWalk(db); tw.reset(); var curs = new WindowCursor(); try { tw.addTree(new CanonicalTreeParser(pathPrefix, db, tree.ToObjectId(), curs)); } finally { curs.release(); } tw.setRecursive(true); if (tw.next()) { DirCacheEntry newEntry = toEntry(stage, tw); beforeAdd(newEntry); fastAdd(newEntry); while (tw.next()) fastAdd(toEntry(stage, tw)); } }