Пример #1
0
  private void execute(final ReceiveCommand cmd) {
    try {
      final RefUpdate ru = db.updateRef(cmd.getRefName());
      ru.setRefLogIdent(getRefLogIdent());
      switch (cmd.getType()) {
        case DELETE:
          if (!ObjectId.zeroId().equals(cmd.getOldId())) {
            // We can only do a CAS style delete if the client
            // didn't bork its delete request by sending the
            // wrong zero id rather than the advertised one.
            //
            ru.setExpectedOldObjectId(cmd.getOldId());
          }
          ru.setForceUpdate(true);
          status(cmd, ru.delete(walk));
          break;

        case CREATE:
        case UPDATE:
        case UPDATE_NONFASTFORWARD:
          ru.setForceUpdate(isAllowNonFastForwards());
          ru.setExpectedOldObjectId(cmd.getOldId());
          ru.setNewObjectId(cmd.getNewId());
          ru.setRefLogMessage("push", true);
          status(cmd, ru.update(walk));
          break;
      }
    } catch (IOException err) {
      cmd.setResult(
          Result.REJECTED_OTHER_REASON,
          MessageFormat.format(JGitText.get().lockError, err.getMessage()));
    }
  }
Пример #2
0
  /**
   * Update a reference to point to an object.
   *
   * @param <T> type of the target object.
   * @param ref the name of the reference to update to. If {@code ref} does not start with {@code
   *     refs/} and is not the magic names {@code HEAD} {@code FETCH_HEAD} or {@code MERGE_HEAD},
   *     then {@code refs/heads/} will be prefixed in front of the given name, thereby assuming it
   *     is a branch.
   * @param obj the target object.
   * @return the target object.
   * @throws Exception
   */
  public <T extends AnyObjectId> T update(String ref, T obj) throws Exception {
    if (Constants.HEAD.equals(ref)) {
      // nothing
    } else if ("FETCH_HEAD".equals(ref)) {
      // nothing
    } else if ("MERGE_HEAD".equals(ref)) {
      // nothing
    } else if (ref.startsWith(Constants.R_REFS)) {
      // nothing
    } else ref = Constants.R_HEADS + ref;

    RefUpdate u = db.updateRef(ref);
    u.setNewObjectId(obj);
    switch (u.forceUpdate()) {
      case FAST_FORWARD:
      case FORCED:
      case NEW:
      case NO_CHANGE:
        updateServerInfo();
        return obj;

      default:
        throw new IOException("Cannot write " + ref + " " + u.getResult());
    }
  }
Пример #3
0
 @NotNull
 @Override
 public Repository createRepository(@NotNull File file, @NotNull String branch)
     throws IOException {
   final Repository repository = createRepository(file);
   final ObjectId revision = createFirstRevision(repository);
   final RefUpdate refUpdate = repository.updateRef(Constants.R_HEADS + branch);
   refUpdate.setNewObjectId(revision);
   refUpdate.update();
   return repository;
 }
  private boolean commitIndex(Repository db, DirCache index, String author, String message)
      throws IOException, ConcurrentRefUpdateException {
    boolean success = false;

    ObjectId headId = db.resolve(BRANCH + "^{commit}");
    if (headId == null) {
      // create the branch
      createTicketsBranch(db);
      headId = db.resolve(BRANCH + "^{commit}");
    }
    try (ObjectInserter odi = db.newObjectInserter()) {
      // Create the in-memory index of the new/updated ticket
      ObjectId indexTreeId = index.writeTree(odi);

      // Create a commit object
      PersonIdent ident = new PersonIdent(author, "[email protected]");
      CommitBuilder commit = new CommitBuilder();
      commit.setAuthor(ident);
      commit.setCommitter(ident);
      commit.setEncoding(Constants.ENCODING);
      commit.setMessage(message);
      commit.setParentId(headId);
      commit.setTreeId(indexTreeId);

      // Insert the commit into the repository
      ObjectId commitId = odi.insert(commit);
      odi.flush();

      try (RevWalk revWalk = new RevWalk(db)) {
        RevCommit revCommit = revWalk.parseCommit(commitId);
        RefUpdate ru = db.updateRef(BRANCH);
        ru.setNewObjectId(commitId);
        ru.setExpectedOldObjectId(headId);
        ru.setRefLogMessage("commit: " + revCommit.getShortMessage(), false);
        Result rc = ru.forceUpdate();
        switch (rc) {
          case NEW:
          case FORCED:
          case FAST_FORWARD:
            success = true;
            break;
          case REJECTED:
          case LOCK_FAILURE:
            throw new ConcurrentRefUpdateException(
                JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
          default:
            throw new JGitInternalException(
                MessageFormat.format(
                    JGitText.get().updatingRefFailed, BRANCH, commitId.toString(), rc));
        }
      }
    }
    return success;
  }
Пример #5
0
 /**
  * Creates a new branch
  *
  * @param refName starting point for the new branch
  * @param newRefName
  * @throws IOException
  */
 public void createBranch(String refName, String newRefName) throws IOException {
   RefUpdate updateRef;
   updateRef = repository.updateRef(newRefName);
   Ref startRef = repository.getRef(refName);
   ObjectId startAt = repository.resolve(refName);
   String startBranch;
   if (startRef != null) startBranch = refName;
   else startBranch = startAt.name();
   startBranch = Repository.shortenRefName(startBranch);
   updateRef.setNewObjectId(startAt);
   updateRef.setRefLogMessage("branch: Created from " + startBranch, false); // $NON-NLS-1$
   updateRef.update();
 }
Пример #6
0
  private void doCheckout(final Ref branch) throws IOException {
    if (branch == null) throw die(CLIText.get().cannotChekoutNoHeadsAdvertisedByRemote);
    if (!Constants.HEAD.equals(branch.getName())) {
      RefUpdate u = db.updateRef(Constants.HEAD);
      u.disableRefLog();
      u.link(branch.getName());
    }

    final RevCommit commit = parseCommit(branch);
    final RefUpdate u = db.updateRef(Constants.HEAD);
    u.setNewObjectId(commit);
    u.forceUpdate();

    DirCache dc = db.lockDirCache();
    DirCacheCheckout co = new DirCacheCheckout(db, dc, commit.getTree());
    co.checkout();
  }
Пример #7
0
  @Test
  public void testListRemote_Smart_DetachedHEAD() throws Exception {
    Repository src = remoteRepository.getRepository();
    RefUpdate u = src.updateRef(Constants.HEAD, true);
    RevCommit Q = remoteRepository.commit().message("Q").create();
    u.setNewObjectId(Q);
    assertEquals(RefUpdate.Result.FORCED, u.forceUpdate());

    Repository dst = createBareRepository();
    Ref head;
    Transport t = Transport.open(dst, smartAuthNoneURI);
    try {
      FetchConnection c = t.openFetch();
      try {
        head = c.getRef(Constants.HEAD);
      } finally {
        c.close();
      }
    } finally {
      t.close();
    }
    assertNotNull("has " + Constants.HEAD, head);
    assertEquals(Q, head.getObjectId());
  }
  @Test
  public void testMergeEmptyBranches()
      throws IOException, NoHeadException, NoMessageException, ConcurrentRefUpdateException,
          JGitInternalException, WrongRepositoryStateException {
    Git git = new Git(db);
    git.commit().setMessage("initial commit").call();
    RefUpdate r = db.updateRef("refs/heads/side");
    r.setNewObjectId(db.resolve(Constants.HEAD));
    assertEquals(r.forceUpdate(), RefUpdate.Result.NEW);
    RevCommit second = git.commit().setMessage("second commit").setCommitter(committer).call();
    db.updateRef(Constants.HEAD).link("refs/heads/side");
    RevCommit firstSide = git.commit().setMessage("first side commit").setAuthor(author).call();

    write(
        new File(db.getDirectory(), Constants.MERGE_HEAD),
        ObjectId.toString(db.resolve("refs/heads/master")));
    write(new File(db.getDirectory(), Constants.MERGE_MSG), "merging");

    RevCommit commit = git.commit().call();
    RevCommit[] parents = commit.getParents();
    assertEquals(parents[0], firstSide);
    assertEquals(parents[1], second);
    assertTrue(parents.length == 2);
  }
Пример #9
0
  /**
   * Executes the {@code commit} command with all the options and parameters collected by the setter
   * methods of this class. Each instance of this class should only be used for one invocation of
   * the command (means: one call to {@link #call()})
   *
   * @return a {@link RevCommit} object representing the successful commit.
   * @throws NoHeadException when called on a git repo without a HEAD reference
   * @throws NoMessageException when called without specifying a commit message
   * @throws UnmergedPathsException when the current index contained unmerged paths (conflicts)
   * @throws ConcurrentRefUpdateException when HEAD or branch ref is updated concurrently by someone
   *     else
   * @throws WrongRepositoryStateException when repository is not in the right state for committing
   * @throws AbortedByHookException if there are either pre-commit or commit-msg hooks present in
   *     the repository and one of them rejects the commit.
   */
  public RevCommit call()
      throws GitAPIException, NoHeadException, NoMessageException, UnmergedPathsException,
          ConcurrentRefUpdateException, WrongRepositoryStateException, AbortedByHookException {
    checkCallable();
    Collections.sort(only);

    try (RevWalk rw = new RevWalk(repo)) {
      RepositoryState state = repo.getRepositoryState();
      if (!state.canCommit())
        throw new WrongRepositoryStateException(
            MessageFormat.format(JGitText.get().cannotCommitOnARepoWithState, state.name()));

      if (!noVerify) {
        Hooks.preCommit(repo, hookOutRedirect).call();
      }

      processOptions(state, rw);

      if (all && !repo.isBare() && repo.getWorkTree() != null) {
        try (Git git = new Git(repo)) {
          git.add()
              .addFilepattern(".") // $NON-NLS-1$
              .setUpdate(true)
              .call();
        } catch (NoFilepatternException e) {
          // should really not happen
          throw new JGitInternalException(e.getMessage(), e);
        }
      }

      Ref head = repo.getRef(Constants.HEAD);
      if (head == null)
        throw new NoHeadException(JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);

      // determine the current HEAD and the commit it is referring to
      ObjectId headId = repo.resolve(Constants.HEAD + "^{commit}"); // $NON-NLS-1$
      if (headId == null && amend)
        throw new WrongRepositoryStateException(JGitText.get().commitAmendOnInitialNotPossible);

      if (headId != null)
        if (amend) {
          RevCommit previousCommit = rw.parseCommit(headId);
          for (RevCommit p : previousCommit.getParents()) parents.add(p.getId());
          if (author == null) author = previousCommit.getAuthorIdent();
        } else {
          parents.add(0, headId);
        }

      if (!noVerify) {
        message = Hooks.commitMsg(repo, hookOutRedirect).setCommitMessage(message).call();
      }

      // lock the index
      DirCache index = repo.lockDirCache();
      try (ObjectInserter odi = repo.newObjectInserter()) {
        if (!only.isEmpty()) index = createTemporaryIndex(headId, index, rw);

        // Write the index as tree to the object database. This may
        // fail for example when the index contains unmerged paths
        // (unresolved conflicts)
        ObjectId indexTreeId = index.writeTree(odi);

        if (insertChangeId) insertChangeId(indexTreeId);

        // Create a Commit object, populate it and write it
        CommitBuilder commit = new CommitBuilder();
        commit.setCommitter(committer);
        commit.setAuthor(author);
        commit.setMessage(message);

        commit.setParentIds(parents);
        commit.setTreeId(indexTreeId);
        ObjectId commitId = odi.insert(commit);
        odi.flush();

        RevCommit revCommit = rw.parseCommit(commitId);
        RefUpdate ru = repo.updateRef(Constants.HEAD);
        ru.setNewObjectId(commitId);
        if (reflogComment != null) {
          ru.setRefLogMessage(reflogComment, false);
        } else {
          String prefix =
              amend
                  ? "commit (amend): " //$NON-NLS-1$
                  : parents.size() == 0
                      ? "commit (initial): " //$NON-NLS-1$
                      : "commit: "; //$NON-NLS-1$
          ru.setRefLogMessage(prefix + revCommit.getShortMessage(), false);
        }
        if (headId != null) ru.setExpectedOldObjectId(headId);
        else ru.setExpectedOldObjectId(ObjectId.zeroId());
        Result rc = ru.forceUpdate();
        switch (rc) {
          case NEW:
          case FORCED:
          case FAST_FORWARD:
            {
              setCallable(false);
              if (state == RepositoryState.MERGING_RESOLVED || isMergeDuringRebase(state)) {
                // Commit was successful. Now delete the files
                // used for merge commits
                repo.writeMergeCommitMsg(null);
                repo.writeMergeHeads(null);
              } else if (state == RepositoryState.CHERRY_PICKING_RESOLVED) {
                repo.writeMergeCommitMsg(null);
                repo.writeCherryPickHead(null);
              } else if (state == RepositoryState.REVERTING_RESOLVED) {
                repo.writeMergeCommitMsg(null);
                repo.writeRevertHead(null);
              }
              return revCommit;
            }
          case REJECTED:
          case LOCK_FAILURE:
            throw new ConcurrentRefUpdateException(
                JGitText.get().couldNotLockHEAD, ru.getRef(), rc);
          default:
            throw new JGitInternalException(
                MessageFormat.format(
                    JGitText.get().updatingRefFailed, Constants.HEAD, commitId.toString(), rc));
        }
      } finally {
        index.unlock();
      }
    } catch (UnmergedPathException e) {
      throw new UnmergedPathsException(e);
    } catch (IOException e) {
      throw new JGitInternalException(
          JGitText.get().exceptionCaughtDuringExecutionOfCommitCommand, e);
    }
  }
Пример #10
0
  /**
   * Update the submodules in one branch of one repository.
   *
   * @param subscriber the branch of the repository which should be changed.
   * @param updates submodule updates which should be updated to.
   * @throws SubmoduleException
   */
  private void updateGitlinks(
      ReviewDb db, Branch.NameKey subscriber, Collection<SubmoduleSubscription> updates)
      throws SubmoduleException {
    PersonIdent author = null;

    Repository pdb = null;
    RevWalk recRw = null;

    StringBuilder msgbuf = new StringBuilder("Updated git submodules\n\n");
    try {
      boolean sameAuthorForAll = true;

      pdb = repoManager.openRepository(subscriber.getParentKey());
      if (pdb.getRef(subscriber.get()) == null) {
        throw new SubmoduleException(
            "The branch was probably deleted from the subscriber repository");
      }

      DirCache dc = readTree(pdb, pdb.getRef(subscriber.get()));
      DirCacheEditor ed = dc.editor();

      for (SubmoduleSubscription s : updates) {
        try (Repository subrepo = repoManager.openRepository(s.getSubmodule().getParentKey());
            RevWalk rw = CodeReviewCommit.newRevWalk(subrepo)) {
          Ref ref = subrepo.getRefDatabase().exactRef(s.getSubmodule().get());
          if (ref == null) {
            ed.add(new DeletePath(s.getPath()));
            continue;
          }

          final ObjectId updateTo = ref.getObjectId();
          RevCommit newCommit = rw.parseCommit(updateTo);

          if (author == null) {
            author = newCommit.getAuthorIdent();
          } else if (!author.equals(newCommit.getAuthorIdent())) {
            sameAuthorForAll = false;
          }

          DirCacheEntry dce = dc.getEntry(s.getPath());
          ObjectId oldId = null;
          if (dce != null) {
            if (!dce.getFileMode().equals(FileMode.GITLINK)) {
              log.error(
                  "Requested to update gitlink "
                      + s.getPath()
                      + " in "
                      + s.getSubmodule().getParentKey().get()
                      + " but entry "
                      + "doesn't have gitlink file mode.");
              continue;
            }
            oldId = dce.getObjectId();
          } else {
            // This submodule did not exist before. We do not want to add
            // the full submodule history to the commit message, so omit it.
            oldId = updateTo;
          }

          ed.add(
              new PathEdit(s.getPath()) {
                @Override
                public void apply(DirCacheEntry ent) {
                  ent.setFileMode(FileMode.GITLINK);
                  ent.setObjectId(updateTo);
                }
              });
          if (verboseSuperProject) {
            msgbuf.append("Project: " + s.getSubmodule().getParentKey().get());
            msgbuf.append(" " + s.getSubmodule().getShortName());
            msgbuf.append(" " + updateTo.getName());
            msgbuf.append("\n\n");

            try {
              rw.markStart(newCommit);

              if (oldId != null) {
                rw.markUninteresting(rw.parseCommit(oldId));
              }
              for (RevCommit c : rw) {
                msgbuf.append(c.getFullMessage() + "\n\n");
              }
            } catch (IOException e) {
              logAndThrowSubmoduleException(
                  "Could not perform a revwalk to " + "create superproject commit message", e);
            }
          }
        }
      }
      ed.finish();

      if (!sameAuthorForAll || author == null) {
        author = myIdent;
      }

      ObjectInserter oi = pdb.newObjectInserter();
      ObjectId tree = dc.writeTree(oi);

      ObjectId currentCommitId = pdb.getRef(subscriber.get()).getObjectId();

      CommitBuilder commit = new CommitBuilder();
      commit.setTreeId(tree);
      commit.setParentIds(new ObjectId[] {currentCommitId});
      commit.setAuthor(author);
      commit.setCommitter(myIdent);
      commit.setMessage(msgbuf.toString());
      oi.insert(commit);
      oi.flush();

      ObjectId commitId = oi.idFor(Constants.OBJ_COMMIT, commit.build());

      final RefUpdate rfu = pdb.updateRef(subscriber.get());
      rfu.setForceUpdate(false);
      rfu.setNewObjectId(commitId);
      rfu.setExpectedOldObjectId(currentCommitId);
      rfu.setRefLogMessage("Submit to " + subscriber.getParentKey().get(), true);

      switch (rfu.update()) {
        case NEW:
        case FAST_FORWARD:
          gitRefUpdated.fire(subscriber.getParentKey(), rfu);
          changeHooks.doRefUpdatedHook(subscriber, rfu, account);
          // TODO since this is performed "in the background" no mail will be
          // sent to inform users about the updated branch
          break;

        default:
          throw new IOException(rfu.getResult().name());
      }
      recRw = new RevWalk(pdb);
      // Recursive call: update subscribers of the subscriber
      updateSuperProjects(db, Sets.newHashSet(subscriber));
    } catch (IOException e) {
      throw new SubmoduleException("Cannot update gitlinks for " + subscriber.get(), e);
    } finally {
      if (recRw != null) {
        recRw.close();
      }
      if (pdb != null) {
        pdb.close();
      }
    }
  }
  @Override
  @Before
  public void setUp() throws Exception {
    super.setUp();

    // create Main Git Repository
    workdir = new File("D://Repository1");

    if (workdir.exists()) {
      FileUtils.delete(workdir, FileUtils.RECURSIVE | FileUtils.RETRY);
    }
    FileUtils.mkdir(workdir, true);

    // init RepositoryUtil class
    repositoryUtil = new RepositoryUtil(new File(workdir, Constants.DOT_GIT));

    repository1 = repositoryUtil.getRepository();

    // create file, add and commit
    File file = new File(workdir, "file.txt");
    FileUtils.createNewFile(file);
    repositoryUtil.appendFileContent(file, "Contect file");
    Git git = new Git(repository1);
    git.add().addFilepattern("file.txt").call();
    git.commit().setMessage("First Commit").call();

    // clone Git Repository 2
    workdir2 = new File("D:/Repository2");

    if (workdir2.exists()) {
      FileUtils.delete(workdir2, FileUtils.RECURSIVE | FileUtils.RETRY);
    }
    FileUtils.mkdir(workdir2, true);

    URIish uri = new URIish("file:///" + repository1.getDirectory().toString());

    CloneOperation clop =
        new CloneOperation(
            uri.toString(), true, null, workdir2, "refs/heads/master", "origin", 0, null, null);
    clop.execute();

    repository2 = new FileRepository(new File(workdir2, Constants.DOT_GIT));

    // clone Git Repository 3
    workdir3 = new File("D:/Repository3");

    if (workdir3.exists()) {
      FileUtils.delete(workdir3, FileUtils.RECURSIVE | FileUtils.RETRY);
    }
    FileUtils.mkdir(workdir3, true);

    uri = new URIish("file:///" + repository1.getDirectory().toString());

    clop =
        new CloneOperation(
            uri.toString(), true, null, workdir3, "refs/heads/master", "origin", 0, null, null);
    clop.execute();

    repository3 = new FileRepository(new File(workdir3, Constants.DOT_GIT));

    RefUpdate createBranch = repository2.updateRef("refs/heads/test");
    createBranch.setNewObjectId(repository2.resolve("refs/heads/master"));
    createBranch.update();
  }
Пример #12
0
  private RefUpdate updateBranch(Branch.NameKey destBranch, IdentifiedUser caller)
      throws IntegrationException {
    RefUpdate branchUpdate = getPendingRefUpdate(destBranch);
    CodeReviewCommit branchTip = getBranchTip(destBranch);

    MergeTip mergeTip = mergeTips.get(destBranch);

    CodeReviewCommit currentTip = mergeTip != null ? mergeTip.getCurrentTip() : null;
    if (Objects.equals(branchTip, currentTip)) {
      if (currentTip != null) {
        logDebug("Branch already at merge tip {}, no update to perform", currentTip.name());
      } else {
        logDebug("Both branch and merge tip are nonexistent, no update");
      }
      return null;
    } else if (currentTip == null) {
      logDebug("No merge tip, no update to perform");
      return null;
    }

    if (RefNames.REFS_CONFIG.equals(branchUpdate.getName())) {
      logDebug("Loading new configuration from {}", RefNames.REFS_CONFIG);
      try {
        ProjectConfig cfg = new ProjectConfig(destProject.getProject().getNameKey());
        cfg.load(repo, currentTip);
      } catch (Exception e) {
        throw new IntegrationException(
            "Submit would store invalid"
                + " project configuration "
                + currentTip.name()
                + " for "
                + destProject.getProject().getName(),
            e);
      }
    }

    branchUpdate.setRefLogIdent(
        identifiedUserFactory.create(caller.getAccountId()).newRefLogIdent());
    branchUpdate.setForceUpdate(false);
    branchUpdate.setNewObjectId(currentTip);
    branchUpdate.setRefLogMessage("merged", true);
    try {
      RefUpdate.Result result = branchUpdate.update(rw);
      logDebug(
          "Update of {}: {}..{} returned status {}",
          branchUpdate.getName(),
          branchUpdate.getOldObjectId(),
          branchUpdate.getNewObjectId(),
          result);
      switch (result) {
        case NEW:
        case FAST_FORWARD:
          if (branchUpdate.getResult() == RefUpdate.Result.FAST_FORWARD) {
            tagCache.updateFastForward(
                destBranch.getParentKey(),
                branchUpdate.getName(),
                branchUpdate.getOldObjectId(),
                currentTip);
          }

          if (RefNames.REFS_CONFIG.equals(branchUpdate.getName())) {
            Project p = destProject.getProject();
            projectCache.evict(p);
            destProject = projectCache.get(p.getNameKey());
            repoManager.setProjectDescription(p.getNameKey(), p.getDescription());
          }

          return branchUpdate;

        case LOCK_FAILURE:
          throw new IntegrationException("Failed to lock " + branchUpdate.getName());
        default:
          throw new IOException(branchUpdate.getResult().name() + '\n' + branchUpdate);
      }
    } catch (IOException e) {
      throw new IntegrationException("Cannot update " + branchUpdate.getName(), e);
    }
  }
Пример #13
0
  /**
   * Execute the SubmoduleUpdateCommand command.
   *
   * @return a collection of updated submodule paths
   * @throws ConcurrentRefUpdateException
   * @throws CheckoutConflictException
   * @throws InvalidMergeHeadsException
   * @throws InvalidConfigurationException
   * @throws NoHeadException
   * @throws NoMessageException
   * @throws RefNotFoundException
   * @throws WrongRepositoryStateException
   * @throws GitAPIException
   */
  public Collection<String> call()
      throws InvalidConfigurationException, NoHeadException, ConcurrentRefUpdateException,
          CheckoutConflictException, InvalidMergeHeadsException, WrongRepositoryStateException,
          NoMessageException, NoHeadException, RefNotFoundException, GitAPIException {
    checkCallable();

    try {
      SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
      if (!paths.isEmpty()) generator.setFilter(PathFilterGroup.createFromStrings(paths));
      List<String> updated = new ArrayList<String>();
      while (generator.next()) {
        // Skip submodules not registered in .gitmodules file
        if (generator.getModulesPath() == null) continue;
        // Skip submodules not registered in parent repository's config
        String url = generator.getConfigUrl();
        if (url == null) continue;

        Repository submoduleRepo = generator.getRepository();
        // Clone repository is not present
        if (submoduleRepo == null) {
          CloneCommand clone = Git.cloneRepository();
          configure(clone);
          clone.setURI(url);
          clone.setDirectory(generator.getDirectory());
          clone.setGitDir(
              new File(new File(repo.getDirectory(), Constants.MODULES), generator.getPath()));
          if (monitor != null) clone.setProgressMonitor(monitor);
          submoduleRepo = clone.call().getRepository();
        }

        try {
          RevWalk walk = new RevWalk(submoduleRepo);
          RevCommit commit = walk.parseCommit(generator.getObjectId());

          String update = generator.getConfigUpdate();
          if (ConfigConstants.CONFIG_KEY_MERGE.equals(update)) {
            MergeCommand merge = new MergeCommand(submoduleRepo);
            merge.include(commit);
            merge.setStrategy(strategy);
            merge.call();
          } else if (ConfigConstants.CONFIG_KEY_REBASE.equals(update)) {
            RebaseCommand rebase = new RebaseCommand(submoduleRepo);
            rebase.setUpstream(commit);
            rebase.setStrategy(strategy);
            rebase.call();
          } else {
            // Checkout commit referenced in parent repository's
            // index as a detached HEAD
            DirCacheCheckout co =
                new DirCacheCheckout(submoduleRepo, submoduleRepo.lockDirCache(), commit.getTree());
            co.setFailOnConflict(true);
            co.checkout();
            RefUpdate refUpdate = submoduleRepo.updateRef(Constants.HEAD, true);
            refUpdate.setNewObjectId(commit);
            refUpdate.forceUpdate();
          }
        } finally {
          submoduleRepo.close();
        }
        updated.add(generator.getPath());
      }
      return updated;
    } catch (IOException e) {
      throw new JGitInternalException(e.getMessage(), e);
    } catch (ConfigInvalidException e) {
      throw new InvalidConfigurationException(e.getMessage(), e);
    }
  }