fix(artifact): put binary macro before merge=ours in generated .gitattributes

gitattributes apply left to right and the binary macro expands to
-diff -merge -text, so the generated line

    graph.db.zst merge=ours binary

leaves the merge attribute UNSET (git check-attr merge reports
"unset"), and concurrent artifact refreshes produce a binary merge
conflict instead of auto-resolving -- the exact failure this file is
generated to prevent. Reordering to

    graph.db.zst binary merge=ours

makes check-attr report merge: ours while keeping -diff/-text intact.

Verified on a real repository: before the reorder git check-attr merge
-- .codebase-memory/graph.db.zst printed "unset"; after, "ours".

Extends artifact_gitattributes_created to pin the ordering so the
regression cannot return.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Alex <plosceac.alexandre@gmail.com>
This commit is contained in:
Alex
2026-07-06 18:23:38 +03:00
co-authored by Claude Fable 5
parent f092d9247e
commit 5f454dd33d
2 changed files with 19 additions and 1 deletions
+5 -1
View File
@@ -382,9 +382,13 @@ static void ensure_gitattributes(const char *repo_path) {
} else {
FILE *fp = fdopen(fd, "w");
if (fp) {
/* Order matters: attributes apply left to right and the `binary`
* macro expands to `-diff -merge -text`, so a trailing `binary`
* unsets `merge=ours` and the conflict prevention this file
* exists for never engages. The macro must come first. */
(void)fputs("# Auto-generated by codebase-memory-mcp\n"
"# Prevent merge conflicts on compressed artifact\n" CBM_ARTIFACT_FILENAME
" merge=ours binary\n",
" binary merge=ours\n",
fp);
(void)fclose(fp);
} else {
+14
View File
@@ -242,6 +242,20 @@ TEST(artifact_gitattributes_created) {
struct stat st;
ASSERT_EQ(stat(ga, &st), 0);
/* Attribute ORDER is load-bearing: gitattributes apply left to right and
* the `binary` macro expands to `-diff -merge -text`, so a trailing
* `binary` unsets a preceding `merge=ours` (git check-attr merge reports
* "unset" and concurrent artifact refreshes produce binary conflicts
* instead of auto-resolving). The driver must come after the macro. */
FILE *gaf = fopen(ga, "r");
ASSERT_NOT_NULL(gaf);
char content[512] = {0};
size_t rd = fread(content, 1, sizeof(content) - 1, gaf);
(void)fclose(gaf);
ASSERT_TRUE(rd > 0);
ASSERT_NOT_NULL(strstr(content, CBM_ARTIFACT_FILENAME " binary merge=ours"));
ASSERT_TRUE(strstr(content, "merge=ours binary") == NULL);
cleanup_dir(g_tmpdir);
PASS();
}