Tucker McKnight <tucker@pangolin.lan> | Sun Feb 01 2026
Add an isMerge attribute to commits Also fix bug where the commit message wasn't being snipped correctly on merge commits. This was because they have the extra metadata line at the top, "Merge," which means the commit message is now five lines down instead of four.
50 51 52 53 54
class: "bezel-gray p-2 my-2",
style: "max-width: 40rem;"
}, [
m('a', {
class: "fs-5",
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/branches/${slugify(data.patchPage.branchName)}/commits/${commit.hash}`,50 51 52 53 54 55
class: "bezel-gray p-2 my-2",
style: "max-width: 40rem;"
}, [
commit.isMerge ? m('span', {class: 'badge rounded-pill bg-primary me-1'}, 'merge') : null,
m('a', {
class: "fs-5",
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/branches/${slugify(data.patchPage.branchName)}/commits/${commit.hash}`,19 20 21 22 23
commits?: Map<string, {
hash: string,
message: string,
author: string,
date: Date,
parent: string | null,19 20 21 22 23 24
commits?: Map<string, {
hash: string,
message: string,
isMerge: boolean,
author: string,
date: Date,
parent: string | null,125 126 127 128 129 130 131 132 133 134 135 136 137
const compareTo = branchDescription.compareTo || reposConfig.repos[repoName].defaultBranch
const compareToBranch = branches.find((test) => test.name === compareTo)
const compareToBranchCommits = new Set()
let currentCommit = commits.get(compareToBranch.head)
while (currentCommit !== undefined) {
compareToBranchCommits.add(currentCommit.hash)
currentCommit = commits.get(currentCommit.parent)
}
const thisBranchCommits = new Set()
currentCommit = commits.get(branch.head)
while (currentCommit !== undefined) {
thisBranchCommits.add(currentCommit.hash)125 126 127 128 129 130 131 132 133 134 135 136 137
const compareTo = branchDescription.compareTo || reposConfig.repos[repoName].defaultBranch
const compareToBranch = branches.find((test) => test.name === compareTo)
const compareToBranchCommits = new Set<string>()
let currentCommit = commits.get(compareToBranch.head)
while (currentCommit !== undefined) {
compareToBranchCommits.add(currentCommit.hash)
currentCommit = commits.get(currentCommit.parent)
}
const thisBranchCommits = new Set<string>()
currentCommit = commits.get(branch.head)
while (currentCommit !== undefined) {
thisBranchCommits.add(currentCommit.hash)141 142 143 144 145 146 147
// At this point, we have all commits in the compareTo branch in one set, and
// all commits from this branch in another set.
const onlyInThisBranch = Array.from(thisBranchCommits).filter(thisBranchCommit => !compareToBranchCommits.has(thisBranchCommit)).length
const onlyInCompareToBranch = Array.from(compareToBranchCommits).filter(compareToBranchCommit => !thisBranchCommits.has(compareToBranchCommit)).length
const compareToInfo = {
ahead: onlyInThisBranch,141 142 143 144 145 146 147 148 149 150 151
// At this point, we have all commits in the compareTo branch in one set, and
// all commits from this branch in another set.
const onlyInThisBranch = Array.from(thisBranchCommits).filter((thisBranchCommit) => {
return !commits.get(thisBranchCommit).isMerge && !compareToBranchCommits.has(thisBranchCommit)
}).length
const onlyInCompareToBranch = Array.from(compareToBranchCommits).filter((compareToBranchCommit) => {
return !commits.get(compareToBranchCommit).isMerge && !thisBranchCommits.has(compareToBranchCommit)
}).length
const compareToInfo = {
ahead: onlyInThisBranch,65 66 67 68 69 70
return
}
let author: string, date: string
[1, 2, 3].forEach((lineNumber) => {
if (currentPatch[lineNumber].startsWith("Author")) {
author = currentPatch[lineNumber].replace("Author: ", "").trim()65 66 67 68 69 70
return
}
let author: string, date: string, isMerge: boolean
[1, 2, 3].forEach((lineNumber) => {
if (currentPatch[lineNumber].startsWith("Author")) {
author = currentPatch[lineNumber].replace("Author: ", "").trim()73 74 75 76 77 78 79 80 81 82 83
else if (currentPatch[lineNumber].startsWith("Date")) {
date = currentPatch[lineNumber].replace("Date: ", "").trim()
}
})
const diffStart = currentPatch.findIndex((line) => {
return line.startsWith("diff ")
})
// Git log is indent four spaces by default -- remove those.
const commitMessage = currentPatch.slice(4, diffStart).map(str => str.replace(" ", "")).filter((line) => {
// git log --porcelain output adds these "Ignore-this:" lines and I'm not sure what they are
return !line.startsWith('Ignore-this: ')
}).join("\n").trim()73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
else if (currentPatch[lineNumber].startsWith("Date")) {
date = currentPatch[lineNumber].replace("Date: ", "").trim()
}
else if (currentPatch[lineNumber].startsWith("Merge")) {
isMerge = true
}
})
let diffStart = currentPatch.findIndex((line) => {
return line.startsWith("diff ")
})
// If no line starts with "diff", this
// is probably a mege commit. Use the last
// line of the patch + 1, in that case, to just get the full
// text of the commit
let messageStart = 4
if (diffStart === -1) {
messageStart = 5
diffStart = currentPatch.length
}
// Git log is indent four spaces by default -- remove those.
const commitMessage = currentPatch.slice(messageStart, diffStart).map(str => str.replace(" ", "")).filter((line) => {
// git log --porcelain output adds these "Ignore-this:" lines and I'm not sure what they are
return !line.startsWith('Ignore-this: ')
}).join("\n").trim()87 88 89 90 91
commits.set(hash, {
hash,
message: commitMessage,
author,
date: new Date(date),
diffs,87 88 89 90 91 92
commits.set(hash, {
hash,
message: commitMessage,
isMerge: isMerge || false,
author,
date: new Date(date),
diffs,