@fern-api/replay 0.10.3 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +53 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +53 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +53 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -173,6 +173,13 @@ declare class ReplayDetector {
|
|
|
173
173
|
* so rebased commits with same content produce the same hash.
|
|
174
174
|
*/
|
|
175
175
|
computeContentHash(patchContent: string): string;
|
|
176
|
+
/**
|
|
177
|
+
* Create a single composite patch for a merge commit by diffing the merge
|
|
178
|
+
* commit against its first parent. This captures the net change of the
|
|
179
|
+
* entire merged branch as one patch, eliminating accumulator chaining and
|
|
180
|
+
* zero-net-change ghost conflicts.
|
|
181
|
+
*/
|
|
182
|
+
private createMergeCompositePatch;
|
|
176
183
|
/**
|
|
177
184
|
* Detect patches via tree diff for non-linear history. Returns a composite patch.
|
|
178
185
|
* Revert reconciliation is skipped here because tree-diff produces a single composite
|
package/dist/index.d.ts
CHANGED
|
@@ -173,6 +173,13 @@ declare class ReplayDetector {
|
|
|
173
173
|
* so rebased commits with same content produce the same hash.
|
|
174
174
|
*/
|
|
175
175
|
computeContentHash(patchContent: string): string;
|
|
176
|
+
/**
|
|
177
|
+
* Create a single composite patch for a merge commit by diffing the merge
|
|
178
|
+
* commit against its first parent. This captures the net change of the
|
|
179
|
+
* entire merged branch as one patch, eliminating accumulator chaining and
|
|
180
|
+
* zero-net-change ghost conflicts.
|
|
181
|
+
*/
|
|
182
|
+
private createMergeCompositePatch;
|
|
176
183
|
/**
|
|
177
184
|
* Detect patches via tree diff for non-linear history. Returns a composite patch.
|
|
178
185
|
* Revert reconciliation is skipped here because tree-diff produces a single composite
|
package/dist/index.js
CHANGED
|
@@ -613,6 +613,7 @@ var ReplayDetector = class {
|
|
|
613
613
|
}
|
|
614
614
|
const log = await this.git.exec([
|
|
615
615
|
"log",
|
|
616
|
+
"--first-parent",
|
|
616
617
|
"--format=%H%x00%an%x00%ae%x00%s",
|
|
617
618
|
`${lastGen.commit_sha}..HEAD`,
|
|
618
619
|
"--",
|
|
@@ -628,11 +629,20 @@ var ReplayDetector = class {
|
|
|
628
629
|
if (isGenerationCommit(commit)) {
|
|
629
630
|
continue;
|
|
630
631
|
}
|
|
631
|
-
|
|
632
|
-
if (parents.length > 1) {
|
|
632
|
+
if (lock.patches.find((p) => p.original_commit === commit.sha)) {
|
|
633
633
|
continue;
|
|
634
634
|
}
|
|
635
|
-
|
|
635
|
+
const parents = await this.git.getCommitParents(commit.sha);
|
|
636
|
+
if (parents.length > 1) {
|
|
637
|
+
const compositePatch = await this.createMergeCompositePatch({
|
|
638
|
+
mergeCommit: commit,
|
|
639
|
+
firstParent: parents[0],
|
|
640
|
+
lastGen,
|
|
641
|
+
lock
|
|
642
|
+
});
|
|
643
|
+
if (compositePatch) {
|
|
644
|
+
newPatches.push(compositePatch);
|
|
645
|
+
}
|
|
636
646
|
continue;
|
|
637
647
|
}
|
|
638
648
|
let patchContent;
|
|
@@ -731,6 +741,46 @@ var ReplayDetector = class {
|
|
|
731
741
|
const normalized = patchContent.split("\n").filter((line) => !line.startsWith("From ") && !line.startsWith("index ") && !line.startsWith("Date: ")).join("\n");
|
|
732
742
|
return `sha256:${createHash("sha256").update(normalized).digest("hex")}`;
|
|
733
743
|
}
|
|
744
|
+
/**
|
|
745
|
+
* Create a single composite patch for a merge commit by diffing the merge
|
|
746
|
+
* commit against its first parent. This captures the net change of the
|
|
747
|
+
* entire merged branch as one patch, eliminating accumulator chaining and
|
|
748
|
+
* zero-net-change ghost conflicts.
|
|
749
|
+
*/
|
|
750
|
+
async createMergeCompositePatch(input) {
|
|
751
|
+
const { mergeCommit, firstParent, lastGen, lock } = input;
|
|
752
|
+
const forgottenHashes = new Set(lock.forgotten_hashes ?? []);
|
|
753
|
+
const filesOutput = await this.git.exec([
|
|
754
|
+
"diff",
|
|
755
|
+
"--name-only",
|
|
756
|
+
firstParent,
|
|
757
|
+
mergeCommit.sha
|
|
758
|
+
]);
|
|
759
|
+
const files = filesOutput.trim().split("\n").filter(Boolean).filter((f) => !INFRASTRUCTURE_FILES.has(f)).filter((f) => !f.startsWith(".fern/"));
|
|
760
|
+
if (files.length === 0) return null;
|
|
761
|
+
const diff = await this.git.exec([
|
|
762
|
+
"diff",
|
|
763
|
+
firstParent,
|
|
764
|
+
mergeCommit.sha,
|
|
765
|
+
"--",
|
|
766
|
+
...files
|
|
767
|
+
]);
|
|
768
|
+
if (!diff.trim()) return null;
|
|
769
|
+
const contentHash = this.computeContentHash(diff);
|
|
770
|
+
if (lock.patches.some((p) => p.content_hash === contentHash) || forgottenHashes.has(contentHash)) {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
return {
|
|
774
|
+
id: `patch-merge-${mergeCommit.sha.slice(0, 8)}`,
|
|
775
|
+
content_hash: contentHash,
|
|
776
|
+
original_commit: mergeCommit.sha,
|
|
777
|
+
original_message: mergeCommit.message,
|
|
778
|
+
original_author: `${mergeCommit.authorName} <${mergeCommit.authorEmail}>`,
|
|
779
|
+
base_generation: lastGen.commit_sha,
|
|
780
|
+
files,
|
|
781
|
+
patch_content: diff
|
|
782
|
+
};
|
|
783
|
+
}
|
|
734
784
|
/**
|
|
735
785
|
* Detect patches via tree diff for non-linear history. Returns a composite patch.
|
|
736
786
|
* Revert reconciliation is skipped here because tree-diff produces a single composite
|