fix(git-rewrite): preserve messages when squashing commits

swadhinbiswas committed 8 months ago
0fdca41
1 parent 0d21323
commit 0fdca41
1 file changed
+15 -15
Showing 1 changed file+15-15
▼src/lib/git-rewrite.ts
+15-15
1
1
2
2
import { simpleGit, SimpleGit } from "simple-git";
3
3
import { acquireRepo, releaseRepo } from "./git-storage";
4
-import { logger } from "./logger";
5
4
6
5
export type RewriteOperation =
7
6
| { type: "pick"; hash: string }
36
35
37
36
// Example: [pick A, squash B, pick C] -> Result: A+B, C.
38
37
39
- let previousCommitWasSquash = false;
40
-
41
38
for (let i = 0; i < operations.length; i++) {
42
39
const op = operations[i];
43
40
47
44
if (op.type === "pick") {
48
45
// git cherry-pick <hash>
49
46
await git.raw(["cherry-pick", op.hash]);
50
- previousCommitWasSquash = false;
51
47
}
52
48
else if (op.type === "reword") {
53
49
await git.raw(["cherry-pick", op.hash]);
54
50
await git.commit(op.newMessage, { "--amend": null });
55
- previousCommitWasSquash = false;
56
51
}
57
52
else if (op.type === "squash") {
58
53
// Squash: cherry-pick -n, then commit --amend (to previous)
59
54
// If first commit is squash, it fails (cannot squash into nothing).
60
55
// We assume valid input from UI.
61
56
57
+ const previousMessage = await readCommitMessage(git, "HEAD");
58
+ const squashMessage = await readCommitMessage(git, op.hash);
59
+
62
60
// 1. Apply changes without commit
63
61
// cherry-pick -n <hash>
64
62
await git.raw(["cherry-pick", "-n", op.hash]);
65
63
66
64
// 2. Amend previous commit
67
- // This reuses previous message + new message?
68
- // simple 'git commit --amend --no-edit' keeps old message.
69
- // Let's just append for now or keep old.
70
- // Ideally we concatenate messages.
71
-
72
- // Only getting subject here, bodies are harder without parsing.
73
- // MVP: Keep previous message (fixup behavior) or just generic amend
74
- await git.commit("", { "--amend": null, "--no-edit": null });
75
-
76
- previousCommitWasSquash = true;
65
+ const combinedMessage = combineCommitMessages(previousMessage, squashMessage);
66
+ await git.commit(combinedMessage, { "--amend": null });
77
67
}
78
68
} catch (e: any) {
79
69
if (e.message.includes("conflict")) {
96
86
await releaseRepo(repoOwner, repoName, true); // True because we pushed
97
87
}
98
88
}
89
+
90
+async function readCommitMessage(git: SimpleGit, rev: string): Promise<string> {
91
+ return (await git.raw(["show", "-s", "--format=%B", rev])).trim();
92
+}
93
+
94
+function combineCommitMessages(previousMessage: string, squashMessage: string): string {
95
+ if (!previousMessage) return squashMessage || "squashed commit";
96
+ if (!squashMessage || previousMessage === squashMessage) return previousMessage;
97
+ return `${previousMessage}\n\n${squashMessage}`.trim();
98
+}
99
99