protected void makeCombination(Map<IndexEntry, Revision> settings) {
    // Assume we are checked out
    String name = "combine-" + tid + "-" + (idx++);
    git.branch(name);
    git.checkout(name);

    String commit = "Hudson generated combination of:\n";

    for (IndexEntry submodule : settings.keySet()) {
      Revision branch = settings.get(submodule);
      commit += "  " + submodule.getFile() + " " + branch.toString() + "\n";
    }

    listener.getLogger().print(commit);

    for (IndexEntry submodule : settings.keySet()) {
      Revision branch = settings.get(submodule);
      File subdir = new File(workspace, submodule.getFile());
      IGitAPI subGit =
          new GitAPI(git.getGitExe(), new FilePath(subdir), listener, git.getEnvironment());

      subGit.checkout(branch.sha1.name());
      git.add(submodule.file);
    }

    git.commit(commit);
  }
  protected void makeCombination(Map<IndexEntry, Revision> settings) {
    // Assume we are checked out
    String name = "combine-" + tid + "-" + (idx++);
    git.branch(name);
    git.checkout(name);

    String commit = "Hudson generated combination of:\n";

    for (IndexEntry submodule : settings.keySet()) {
      Revision branch = settings.get(submodule);
      commit += "  " + submodule.getFile() + " " + branch.toString() + "\n";
    }

    listener.getLogger().print(commit);

    for (IndexEntry submodule : settings.keySet()) {
      Revision branch = settings.get(submodule);
      File subdir = new File(workspace, submodule.getFile());
      IGitAPI subGit =
          new GitAPI(git.getGitExe(), new FilePath(subdir), listener, git.getEnvironment());

      subGit.checkout(branch.sha1.name());
      git.add(submodule.file);
    }

    try {
      File f = File.createTempFile("gitcommit", ".txt");
      FileOutputStream fos = null;
      try {
        fos = new FileOutputStream(f);
        fos.write(commit.getBytes());
      } finally {
        fos.close();
      }
      git.commit(f);
      f.delete();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  public void createSubmoduleCombinations() throws GitException, IOException {
    Map<IndexEntry, Collection<Revision>> moduleBranches =
        new HashMap<IndexEntry, Collection<Revision>>();

    for (IndexEntry submodule : git.getSubmodules("HEAD")) {
      File subdir = new File(workspace, submodule.getFile());
      IGitAPI subGit =
          new GitAPI(git.getGitExe(), new FilePath(subdir), listener, git.getEnvironment());

      GitUtils gu = new GitUtils(listener, subGit);
      Collection<Revision> items = gu.filterTipBranches(gu.getAllBranchRevisions());

      filterRevisions(submodule.getFile(), items);

      moduleBranches.put(submodule, items);
    }

    // Remove any uninteresting branches

    for (IndexEntry entry : moduleBranches.keySet()) {
      listener.getLogger().print("Submodule " + entry.getFile() + " branches");
      for (Revision br : moduleBranches.get(entry)) {
        listener.getLogger().print(" " + br.toString());
      }
      listener.getLogger().print("\n");
    }

    // Make all the possible combinations
    List<Map<IndexEntry, Revision>> combinations = createCombinations(moduleBranches);

    listener
        .getLogger()
        .println("There are " + combinations.size() + " submodule/revision combinations possible");

    // Create a map which is SHA1 -> Submodule IDs that were present
    Map<ObjectId, List<IndexEntry>> entriesMap = new HashMap<ObjectId, List<IndexEntry>>();
    // Knock out already-defined configurations
    for (ObjectId sha1 : git.revListAll()) {
      // What's the submodule configuration
      List<IndexEntry> entries = git.getSubmodules(sha1.name());
      entriesMap.put(sha1, entries);
    }

    for (List<IndexEntry> entries : entriesMap.values()) {
      for (Iterator<Map<IndexEntry, Revision>> it = combinations.iterator(); it.hasNext(); ) {
        Map<IndexEntry, Revision> item = it.next();
        if (matches(item, entries)) {
          it.remove();
          break;
        }
      }
    }

    listener
        .getLogger()
        .println("There are " + combinations.size() + " configurations that could be generated.");

    ObjectId headSha1 = git.revParse("HEAD");

    // Make up the combinations

    for (Map<IndexEntry, Revision> combination : combinations) {
      // By default, use the head sha1
      ObjectId sha1 = headSha1;
      int min = Integer.MAX_VALUE;

      // But let's see if we can find the most appropriate place to create the branch
      for (ObjectId sha : entriesMap.keySet()) {
        List<IndexEntry> entries = entriesMap.get(sha);
        int value = difference(combination, entries);
        if (value > 0 && value < min) {
          min = value;
          sha1 = sha;
        }

        if (min == 1) {
          break; // look no further
        }
      }

      git.checkout(sha1.name());
      makeCombination(combination);
    }
  }