Beispiel #1
0
  @Test
  public void testPathsResetWithUnmerged() throws Exception {
    setupRepository();

    String file = "a.txt";
    writeTrashFile(file, "data");

    git.add().addFilepattern(file).call();
    git.commit().setMessage("commit").call();

    DirCache index = db.lockDirCache();
    DirCacheBuilder builder = index.builder();
    builder.add(createEntry(file, FileMode.REGULAR_FILE, 1, ""));
    builder.add(createEntry(file, FileMode.REGULAR_FILE, 2, ""));
    builder.add(createEntry(file, FileMode.REGULAR_FILE, 3, ""));
    builder.add(createEntry("b.txt", FileMode.REGULAR_FILE));
    assertTrue(builder.commit());

    assertEquals(
        "[a.txt, mode:100644, stage:1]"
            + "[a.txt, mode:100644, stage:2]"
            + "[a.txt, mode:100644, stage:3]"
            + "[b.txt, mode:100644]",
        indexState(0));

    git.reset().addPath(file).call();

    assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]", indexState(0));
  }
Beispiel #2
0
  /**
   * The resolve conflict way of three way merging
   *
   * @param baseTree
   * @param headTree
   * @param mergeTree
   * @param ignoreConflicts Controls what to do in case a content-merge is done and a conflict is
   *     detected. The default setting for this should be <code>false</code>. In this case the
   *     working tree file is filled with new content (containing conflict markers) and the index is
   *     filled with multiple stages containing BASE, OURS and THEIRS content. Having such non-0
   *     stages is the sign to git tools that there are still conflicts for that path.
   *     <p>If <code>true</code> is specified the behavior is different. In case a conflict is
   *     detected the working tree file is again filled with new content (containing conflict
   *     markers). But also stage 0 of the index is filled with that content. No other stages are
   *     filled. Means: there is no conflict on that path but the new content (including conflict
   *     markers) is stored as successful merge result. This is needed in the context of {@link
   *     RecursiveMerger} where when determining merge bases we don't want to deal with
   *     content-merge conflicts.
   * @return whether the trees merged cleanly
   * @throws IOException
   * @since 3.5
   */
  protected boolean mergeTrees(
      AbstractTreeIterator baseTree, RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
      throws IOException {

    builder = dircache.builder();
    DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder);

    tw = new NameConflictTreeWalk(reader);
    tw.addTree(baseTree);
    tw.addTree(headTree);
    tw.addTree(mergeTree);
    tw.addTree(buildIt);
    if (workingTreeIterator != null) {
      tw.addTree(workingTreeIterator);
    } else {
      tw.setFilter(TreeFilter.ANY_DIFF);
    }

    if (!mergeTreeWalk(tw, ignoreConflicts)) {
      return false;
    }

    if (!inCore) {
      // No problem found. The only thing left to be done is to
      // checkout all files from "theirs" which have been selected to
      // go into the new index.
      checkout();

      // All content-merges are successfully done. If we can now write the
      // new index we are on quite safe ground. Even if the checkout of
      // files coming from "theirs" fails the user can work around such
      // failures by checking out the index again.
      if (!builder.commit()) {
        cleanUp();
        throw new IndexWriteException();
      }
      builder = null;

    } else {
      builder.finish();
      builder = null;
    }

    if (getUnmergedPaths().isEmpty() && !failed()) {
      resultTree = dircache.writeTree(getObjectInserter());
      return true;
    } else {
      resultTree = null;
      return false;
    }
  }
Beispiel #3
0
  private void verifyStageState(StageState expected, int... stages) throws IOException {
    DirCacheBuilder builder = db.lockDirCache().builder();
    for (int stage : stages) {
      DirCacheEntry entry = createEntry("a", FileMode.REGULAR_FILE, stage, "content");
      builder.add(entry);
    }
    builder.commit();

    IndexDiff diff = new IndexDiff(db, Constants.HEAD, new FileTreeIterator(db));
    diff.diff();

    assertEquals(
        "Conflict for entries in stages " + Arrays.toString(stages),
        expected,
        diff.getConflictingStageStates().get("a"));
  }
Beispiel #4
0
  @Test
  public void testStageState_simulated_bug() throws Exception {
    try (Git git = new Git(db)) {
      writeTrashFile("a", "content");
      git.add().addFilepattern("a").call();
      RevCommit initialCommit = git.commit().setMessage("initial commit").call();

      // create branch and add a new file
      final String branchName = Constants.R_HEADS + "branch";
      createBranch(initialCommit, branchName);
      checkoutBranch(branchName);
      writeTrashFile("b", "second file content - branch");
      git.add().addFilepattern("b").call();
      git.commit().setMessage("branch commit").call();

      // checkout master and add the same new file
      checkoutBranch(Constants.R_HEADS + Constants.MASTER);
      writeTrashFile("b", "second file content - master");
      git.add().addFilepattern("b").call();
      git.commit().setMessage("master commit").call();

      // Simulate a failed merge of branch into master
      DirCacheBuilder builder = db.lockDirCache().builder();
      DirCacheEntry entry = createEntry("a", FileMode.REGULAR_FILE, 0, "content");
      builder.add(entry);
      entry = createEntry("b", FileMode.REGULAR_FILE, 2, "second file content - master");
      builder.add(entry);
      entry = createEntry("b", FileMode.REGULAR_FILE, 3, "second file content - branch");
      builder.add(entry);
      builder.commit();

      FileTreeIterator iterator = new FileTreeIterator(db);
      IndexDiff diff = new IndexDiff(db, Constants.HEAD, iterator);
      diff.diff();

      assertTrue(diff.getChanged().isEmpty());
      assertTrue(diff.getAdded().isEmpty());
      assertTrue(diff.getRemoved().isEmpty());
      assertTrue(diff.getMissing().isEmpty());
      assertTrue(diff.getModified().isEmpty());
      assertEquals(1, diff.getConflicting().size());
      assertTrue(diff.getConflicting().contains("b"));
      assertEquals(StageState.BOTH_ADDED, diff.getConflictingStageStates().get("b"));
      assertTrue(diff.getUntrackedFolders().isEmpty());
    }
  }
Beispiel #5
0
  private DirCache createTemporaryIndex(ObjectId headId, DirCache index, RevWalk rw)
      throws IOException {
    ObjectInserter inserter = null;

    // get DirCacheBuilder for existing index
    DirCacheBuilder existingBuilder = index.builder();

    // get DirCacheBuilder for newly created in-core index to build a
    // temporary index for this commit
    DirCache inCoreIndex = DirCache.newInCore();
    DirCacheBuilder tempBuilder = inCoreIndex.builder();

    onlyProcessed = new boolean[only.size()];
    boolean emptyCommit = true;

    try (TreeWalk treeWalk = new TreeWalk(repo)) {
      treeWalk.setOperationType(OperationType.CHECKIN_OP);
      int dcIdx = treeWalk.addTree(new DirCacheBuildIterator(existingBuilder));
      FileTreeIterator fti = new FileTreeIterator(repo);
      fti.setDirCacheIterator(treeWalk, 0);
      int fIdx = treeWalk.addTree(fti);
      int hIdx = -1;
      if (headId != null) hIdx = treeWalk.addTree(rw.parseTree(headId));
      treeWalk.setRecursive(true);

      String lastAddedFile = null;
      while (treeWalk.next()) {
        String path = treeWalk.getPathString();
        // check if current entry's path matches a specified path
        int pos = lookupOnly(path);

        CanonicalTreeParser hTree = null;
        if (hIdx != -1) hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);

        DirCacheIterator dcTree = treeWalk.getTree(dcIdx, DirCacheIterator.class);

        if (pos >= 0) {
          // include entry in commit

          FileTreeIterator fTree = treeWalk.getTree(fIdx, FileTreeIterator.class);

          // check if entry refers to a tracked file
          boolean tracked = dcTree != null || hTree != null;
          if (!tracked) continue;

          // for an unmerged path, DirCacheBuildIterator will yield 3
          // entries, we only want to add one
          if (path.equals(lastAddedFile)) continue;

          lastAddedFile = path;

          if (fTree != null) {
            // create a new DirCacheEntry with data retrieved from
            // disk
            final DirCacheEntry dcEntry = new DirCacheEntry(path);
            long entryLength = fTree.getEntryLength();
            dcEntry.setLength(entryLength);
            dcEntry.setLastModified(fTree.getEntryLastModified());
            dcEntry.setFileMode(fTree.getIndexFileMode(dcTree));

            boolean objectExists =
                (dcTree != null && fTree.idEqual(dcTree))
                    || (hTree != null && fTree.idEqual(hTree));
            if (objectExists) {
              dcEntry.setObjectId(fTree.getEntryObjectId());
            } else {
              if (FileMode.GITLINK.equals(dcEntry.getFileMode()))
                dcEntry.setObjectId(fTree.getEntryObjectId());
              else {
                // insert object
                if (inserter == null) inserter = repo.newObjectInserter();
                long contentLength = fTree.getEntryContentLength();
                InputStream inputStream = fTree.openEntryStream();
                try {
                  dcEntry.setObjectId(
                      inserter.insert(Constants.OBJ_BLOB, contentLength, inputStream));
                } finally {
                  inputStream.close();
                }
              }
            }

            // add to existing index
            existingBuilder.add(dcEntry);
            // add to temporary in-core index
            tempBuilder.add(dcEntry);

            if (emptyCommit
                && (hTree == null
                    || !hTree.idEqual(fTree)
                    || hTree.getEntryRawMode() != fTree.getEntryRawMode()))
              // this is a change
              emptyCommit = false;
          } else {
            // if no file exists on disk, neither add it to
            // index nor to temporary in-core index

            if (emptyCommit && hTree != null)
              // this is a change
              emptyCommit = false;
          }

          // keep track of processed path
          onlyProcessed[pos] = true;
        } else {
          // add entries from HEAD for all other paths
          if (hTree != null) {
            // create a new DirCacheEntry with data retrieved from
            // HEAD
            final DirCacheEntry dcEntry = new DirCacheEntry(path);
            dcEntry.setObjectId(hTree.getEntryObjectId());
            dcEntry.setFileMode(hTree.getEntryFileMode());

            // add to temporary in-core index
            tempBuilder.add(dcEntry);
          }

          // preserve existing entry in index
          if (dcTree != null) existingBuilder.add(dcTree.getDirCacheEntry());
        }
      }
    }

    // there must be no unprocessed paths left at this point; otherwise an
    // untracked or unknown path has been specified
    for (int i = 0; i < onlyProcessed.length; i++)
      if (!onlyProcessed[i])
        throw new JGitInternalException(
            MessageFormat.format(JGitText.get().entryNotFoundByPath, only.get(i)));

    // there must be at least one change
    if (emptyCommit) throw new JGitInternalException(JGitText.get().emptyCommit);

    // update index
    existingBuilder.commit();
    // finish temporary in-core index used for this commit
    tempBuilder.finish();
    return inCoreIndex;
  }