public CommitDiffPage(PageParameters params) {
    super(params);

    Repository r = getRepository();

    final RevCommit commit = getCommit();

    final List<String> parents = new ArrayList<String>();
    if (commit.getParentCount() > 0) {
      for (RevCommit parent : commit.getParents()) {
        parents.add(parent.name());
      }
    }

    // commit page links
    if (parents.size() == 0) {
      add(new Label("parentLink", getString("gb.none")));
    } else {
      add(
          new LinkPanel(
              "parentLink",
              null,
              parents.get(0).substring(0, 8),
              CommitDiffPage.class,
              newCommitParameter(parents.get(0))));
    }
    add(
        new BookmarkablePageLink<Void>(
            "patchLink",
            PatchPage.class,
            WicketUtils.newObjectParameter(repositoryName, objectId)));
    add(
        new BookmarkablePageLink<Void>(
            "commitLink",
            CommitPage.class,
            WicketUtils.newObjectParameter(repositoryName, objectId)));

    add(new CommitHeaderPanel("commitHeader", repositoryName, commit));

    final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
    final ImageDiffHandler handler =
        new ImageDiffHandler(
            this,
            repositoryName,
            parents.isEmpty() ? null : parents.get(0),
            commit.getName(),
            imageExtensions);
    final DiffOutput diff = DiffUtils.getCommitDiff(r, commit, DiffOutputType.HTML, handler);
    if (handler.getImgDiffCount() > 0) {
      addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
    }

    // add commit diffstat
    int insertions = 0;
    int deletions = 0;
    for (PathChangeModel pcm : diff.stat.paths) {
      insertions += pcm.insertions;
      deletions += pcm.deletions;
    }
    add(new DiffStatPanel("diffStat", insertions, deletions));

    addFullText("fullMessage", commit.getFullMessage());

    // git notes
    List<GitNote> notes = JGitUtils.getNotesOnCommit(r, commit);
    ListDataProvider<GitNote> notesDp = new ListDataProvider<GitNote>(notes);
    DataView<GitNote> notesView =
        new DataView<GitNote>("notes", notesDp) {
          private static final long serialVersionUID = 1L;

          @Override
          public void populateItem(final Item<GitNote> item) {
            GitNote entry = item.getModelObject();
            item.add(new RefsPanel("refName", repositoryName, Arrays.asList(entry.notesRef)));
            item.add(
                createPersonPanel(
                    "authorName", entry.notesRef.getAuthorIdent(), Constants.SearchType.AUTHOR));
            item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent()));
            item.add(
                WicketUtils.createTimestampLabel(
                    "authorDate",
                    entry.notesRef.getAuthorIdent().getWhen(),
                    getTimeZone(),
                    getTimeUtils()));
            item.add(
                new Label(
                        "noteContent",
                        bugtraqProcessor()
                            .processPlainCommitMessage(
                                getRepository(), repositoryName, entry.content))
                    .setEscapeModelStrings(false));
          }
        };
    add(notesView.setVisible(notes.size() > 0));

    // changed paths list
    add(new CommitLegendPanel("commitLegend", diff.stat.paths));
    ListDataProvider<PathChangeModel> pathsDp =
        new ListDataProvider<PathChangeModel>(diff.stat.paths);
    DataView<PathChangeModel> pathsView =
        new DataView<PathChangeModel>("changedPath", pathsDp) {
          private static final long serialVersionUID = 1L;
          int counter;

          @Override
          public void populateItem(final Item<PathChangeModel> item) {
            final PathChangeModel entry = item.getModelObject();
            Label changeType = new Label("changeType", "");
            WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
            setChangeTypeTooltip(changeType, entry.changeType);
            item.add(changeType);
            item.add(new DiffStatPanel("diffStat", entry.insertions, entry.deletions, true));

            boolean hasSubmodule = false;
            String submodulePath = null;
            if (entry.isTree()) {
              // tree
              item.add(
                  new LinkPanel(
                      "pathName",
                      null,
                      entry.path,
                      TreePage.class,
                      WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
            } else if (entry.isSubmodule()) {
              // submodule
              String submoduleId = entry.objectId;
              SubmoduleModel submodule = getSubmodule(entry.path);
              submodulePath = submodule.gitblitPath;
              hasSubmodule = submodule.hasSubmodule;

              // add relative link
              item.add(
                  new LinkPanel(
                      "pathName",
                      "list",
                      entry.path + " @ " + getShortObjectId(submoduleId),
                      "#n" + entry.objectId));
            } else {
              // add relative link
              item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId));
            }

            // quick links
            if (entry.isSubmodule()) {
              item.add(new ExternalLink("raw", "").setEnabled(false));
              // submodule
              item.add(new ExternalLink("patch", "").setEnabled(false));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "view",
                          CommitPage.class,
                          WicketUtils.newObjectParameter(submodulePath, entry.objectId))
                      .setEnabled(hasSubmodule));
              item.add(new ExternalLink("blame", "").setEnabled(false));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "history",
                          HistoryPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
            } else {
              // tree or blob
              item.add(
                  new BookmarkablePageLink<Void>(
                          "patch",
                          PatchPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(
                          !entry.changeType.equals(ChangeType.ADD)
                              && !entry.changeType.equals(ChangeType.DELETE)));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "view",
                          BlobPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
              String rawUrl =
                  RawServlet.asLink(getContextUrl(), repositoryName, entry.commitId, entry.path);
              item.add(
                  new ExternalLink("raw", rawUrl)
                      .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "blame",
                          BlamePage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(
                          !entry.changeType.equals(ChangeType.ADD)
                              && !entry.changeType.equals(ChangeType.DELETE)));
              item.add(
                  new BookmarkablePageLink<Void>(
                          "history",
                          HistoryPage.class,
                          WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path))
                      .setEnabled(!entry.changeType.equals(ChangeType.ADD)));
            }

            WicketUtils.setAlternatingBackground(item, counter);
            counter++;
          }
        };
    add(pathsView);
    add(new Label("diffText", diff.content).setEscapeModelStrings(false));
  }