SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth - #3

Open
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version
Open

SERVER-1410 - Track VERSION so the version doesn't depend on clone depth#3
AerospikeNate-L wants to merge 2 commits into
asd-4.5.0from
nel/SERVER-1410-jemalloc-tracked-version

Conversation

@AerospikeNate-L

@AerospikeNate-LAerospikeNate-L commented Aug 27, 2026

Copy link
Copy Markdown

Draft — opening for direction, not merge-readiness. @pvinh-spike, you're the reviewer I want on this because the answer depends on how much liberty we have to patch this fork.

Problem

configure.ac derives jemalloc's version from git describe and, when that fails, falls through to a hardcoded bogus value that gets compiled into the library:

Missing VERSION file, and unable to generate it; creating bogus VERSION
0.0.0-0-g0000000000000000000000000000000000000000

describe needs the nearest ancestor tag in the graph. Our pin (8c87a080) sits 5 commits past 4.5.0, so any clone shallower than depth 6 silently produces that bogus string. A --depth 1 fetch does bring 45 tags, but none of them is an ancestor of the grafted commit.

This is live today: the QE/bob pipeline clones submodules at --depth 1, GitHub Actions clones them in full, so the binaries QE validates carry a different JEMALLOC_VERSION than the ones we ship. Same failure hits builds from the public .src.tar.bz2, which has no .git at all (pkg/src/git-cp-files.sh copies git ls-files output).

Context: SERVER-1410 / QE-1079. jemalloc is the only submodule that derives a build value from git history — swept all 14, and the other two hits (icu's dist.mk, json's Makefile) are in targets the server build never invokes.

Fix — two parts, both needed

1. Track a new file, VERSION.src. Content is the verbatim output of the same git describe --long --abbrev=40 invocation configure runs. VERSION itself stays gitignored and generated — see Why a separate file below.

2. Let VERSION.src win over git describe in configure.ac. Part 1 alone does not close the gap — I measured it. Adding the file creates a commit, so the tracked value can never describe the commit that contains it; on a deep clone describe succeeds and overwrites the generated VERSION:

clonepart 1 onlyparts 1+2
--depth 14.5.0-5-g8c87a080…4.5.0-5-g8c87a080…
deep4.5.0-6-g54dda05b… ← still divergent4.5.0-5-g8c87a080…
no .git (source archive)4.5.0-5-g8c87a080…4.5.0-5-g8c87a080…

The change is one new branch ahead of the existing git describe block, inside the arm that already only runs when --with-version wasn't passed:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

--with-version still takes precedence and still hard-errors on a malformed value — both re-verified.

Why a separate file rather than tracking VERSION

The first revision of this PR tracked VERSION itself. @cinterloper found that this makes one path both a tracked input and a generated output, which breaks in two places (thanks — both reproduced):

  • Makefile.in:487relclean runs rm -f $(objroot)VERSION. In an in-tree build that deletes the tracked file, and the next configure regenerates a different value from describe.
  • configure.ac:1306--with-version writes the override to ${objroot}VERSION, i.e. over the tracked file. The existence guard then keeps that override forever, and the checkout is left dirty.

With VERSION.src as the tracked input, VERSION keeps its upstream role as a generated artifact, and both of those paths behave exactly as upstream intends: relclean deletes a generated file, --with-version overwrites a generated file, and the next plain configure restores the canonical value from VERSION.src.

This reverts a 2010 upstream decision — knowingly

a40bc7af ("Add release versioning support", Jason Evans, 2010-03-02) deleted the then-tracked VERSION and added /VERSION to .gitignore in the same commit. The file it removed contained a stale hand-maintained 0.0.0, which is why he moved to git describe.

Upstream's model after that: VERSION is generated inside a checkout and shipped inside the release tarball. Makefile.in:487 only removes it under relclean, never distclean, so tarball consumers keep it; INSTALL:40 documents the precedence as --with-versiongit describe → existing VERSION file, that last tier existing for exactly those consumers.

Both halves of that assumption fail for us:

  • a shallow clone is inside git but cannot derive the value
  • our source package is built by pkg/src/git-cp-files.sh copying git ls-files output — tracked files only. We never invoke jemalloc's make dist, so the generated-then-shipped VERSION a genuine jemalloc tarball carries never reaches ours.

The configure.ac change therefore inserts a new tier above git describe — a tracked VERSION.src now beats describe. That is a deliberate fork divergence, not a bug fix, and it is the part I most want your read on. It is safe for us because we never consume this fork as an upstream-style dist tarball, and --with-version still overrides everything. Upstream's own three tiers are left intact underneath.

Related: Makefile:195GIT_CLEAN = git clean -fdx, run by the server's make cleangit, deletes the generated VERSION today. The tracked VERSION.src survives it, and configure regenerates VERSION from it.

Verified

autoconf && ./configure --with-jemalloc-prefix=jem_ --with-lg-page=12 on this branch:

  • deep clone, --depth 1 clone, and git archive export (no .git) all produce 4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb, with no "bogus VERSION" message
  • make include/jemalloc/jemalloc.h#define JEMALLOC_VERSION "4.5.0-5-g8c87a080f0a88375169faeba0f4358b81dcc27bb"
  • control (depth-1 clone of asd-4.5.0 without this change) reproduces 0.0.0-0-g0000…
  • make relclean in an in-tree deep clone: VERSION removed, VERSION.src untouched, git status clean, reconfigure restores the canonical string
  • --with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense errors out

The server builds this in-tree (Makefile:233cd $(JEMALLOC) && ./configure), so objroot = srcroot = empty, and Makefile:230 runs autoconf at build time — the configure.ac change takes effect without a regenerated configure needing to be tracked.

What this asks of us going forward

VERSION.src names the last code-bearing commit, not the tip. The commits adding it change no code, so the string stays accurate about what's compiled — but bumping this pin means regenerating VERSION.src in the same push, and if someone forgets, we ship a valid but stale string instead of a loud failure. That's the tradeoff I'd like your read on.

The alternative I considered and rejected: --with-version=… in the server's JEM_CONFIG_OPT (make_in/Makefile.vars:53). Same staleness exposure, but the constant lives in a different repo from the commit it describes, so a pin bump silently desyncs. Keeping the value next to the code it names is the only real difference — worth it, I think, but it's the reason this touches configure.ac at all.

If you'd rather not carry a local patch on the fork, say so and I'll take the --with-version route instead and close this.

Once this lands, the server-side pin bump follows, then both pipelines can align on --depth 1 (drops ICU from 445 MB → 61 MB and retires the source-tarball size ceiling that started this).

🤖 Generated with Claude Code

configure.ac derives the version from `git describe`, and when that fails it
falls through to a hardcoded 0.0.0-0-g0000... that gets compiled into the
library. `describe` needs the nearest ancestor tag in the graph; this pin sits
5 commits past 4.5.0, so any clone shallower than depth 6 silently produces
the bogus value. Builds from a source distribution with no .git at all hit the
same path.
configure only reaches the git branch when VERSION does not already exist, so
a tracked file short-circuits it: shallow clones keep the committed value, and
deep clones regenerate the identical string. The value here is the output of
the same `git describe --long --abbrev=40` invocation configure runs.
Bumping this pin means regenerating VERSION in the same commit.
SERVER-1410
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L
AerospikeNate-L marked this pull request as ready for review August 27, 2026 20:35

@cinterlopercinterloper left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reproduced the intended behavior in fresh full and depth-1 clones, but found two cases where using VERSION as both a tracked input and generated output breaks the determinism this change is meant to provide.

  1. relclean deletes the tracked version input.Makefile.in:487 still runs rm -f $(objroot)VERSION. In an in-tree build, make relclean therefore deletes the tracked file. The next configure changes the version to 4.5.0-6-g54dda... in a full clone and to the bogus 0.0.0-0-g0000... value in a depth-1 clone. It also leaves the checkout with VERSION deleted or modified.

  2. --with-version permanently overwrites the tracked default.configure.ac:1306 writes the override to ${objroot}VERSION, which is the tracked source file for an in-tree build. The new existence guard then prevents the next ordinary configure from restoring the committed value. I reproduced this with --with-version=4.5.0-99-gdeadbeef; a subsequent configure without --with-version retained that override and left VERSION modified.

I suggest tracking a distinct immutable input such as VERSION.src, keeping VERSION as generated output, and copying the canonical input into objroot/VERSION. That avoids collisions with both relclean and --with-version while preserving the shallow-clone and source-archive fix.

The current GitHub checks are security checks only and do not exercise these configure paths.

Using VERSION as both a tracked input and a generated output collides
with `make relclean`, which deletes it, and with --with-version, which
overwrites it and then loses to the existence guard on the next
configure. Track VERSION.src instead and copy it into objroot/VERSION.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AerospikeNate-L

Copy link
Copy Markdown
Author

Good catch on both — you're right that using one path as tracked input and generated output is the root of it, and I reproduced both cases before changing anything. Applied your suggestion in de00f42.

VERSION.src is now the tracked input; VERSION goes back to being gitignored and generated, and the guard copies the canonical input into objroot/VERSION:

if test -e "${srcroot}VERSION.src" ; then
cp "${srcroot}VERSION.src" "${objroot}VERSION"
elif test "x`… git rev-parse --is-inside-work-tree …`" = "xtrue" ; then

Makefile.in:487 and the --with-version write both keep their upstream meaning — they act on a generated file — so neither can touch anything tracked.

Re-verified on top of the change:

  • deep clone, --depth 1 clone, and git archive export (no .git) all give 4.5.0-5-g8c87a080…, no "bogus VERSION" message; generated header carries the same string
  • your case 1:make relclean in an in-tree deep clone removes VERSION, leaves VERSION.src untouched and git status clean; the next configure restores the canonical string rather than 4.5.0-6-g54dda05b…
  • your case 2:--with-version=4.5.0-99-gdeadbeef… overrides and leaves git status clean; the next plain configure restores the canonical string
  • --with-version=nonsense still hard-errors

INSTALL and the PR description are updated for the new precedence tier. Agreed the GitHub checks don't cover these paths — everything above is local, recipe in the Verified section if you want to repeat it.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@AerospikeNate-L@cinterloper