Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
9b2d7d0
fix(test): a later passing @expect no longer clears an earlier failur…
claude Oct 28, 2026
be9dc02
fix(test): rename a lower-case `call`/`create` variable per test on t…
claude Oct 28, 2026
2f9b626
fix(security): keep a module role's description when create or modify…
claude Oct 28, 2026
7f0d71e
fix(modelsdk): declare AggregateFunction on Mendix 9, floor Reduce's …
claude Oct 28, 2026
57cb317
fix(canon): write no workflow PersistentId below Mendix 10.21
claude Oct 28, 2026
2c7876b
fix(canon): complete a workflow's state-change handlers on Mendix 9.24
claude Oct 28, 2026
4df889e
fix(canon): write a constant override flat below Mendix 10.9
claude Oct 28, 2026
de548c6
fix(canon): leave a $currentObject flow argument out below Mendix 10.10
claude Oct 28, 2026
baaeda1
fix(executor): gate create published odata service at Mendix 10.4
claude Oct 28, 2026
c190ea7
docs(wiki): a version refusal is not always an older shape
claude Oct 28, 2026
8af923f
Merge pull request #1764 from ako/claude/loving-clarke-qun7w5
ako Oct 28, 2026
42778ae
fix(test): git doctor tests no longer read the developer's git config
claude Oct 28, 2026
e29655c
Merge pull request #1765 from ako/claude/loving-clarke-qun7w5
ako Oct 28, 2026
a6f3dfa
fix(make): fmt-check uses the toolchain's gofmt, not the one on PATH
claude Oct 28, 2026
f4398e6
build(make): add ci-local, the build-and-test job run before pushing
claude Oct 28, 2026
880a284
docs(skills): add the steward skill, the loop from PR opened to merged
claude Oct 28, 2026
277bf8e
fix(git): doctor judges notes only once the remote's notes are fetched
claude Oct 28, 2026
61af7ee
fix(git): doctor judges the configured remote URL, not the insteadOf …
claude Oct 28, 2026
eac6fbf
fix(git): commit --dry-run leaves what the user staged as it was
claude Oct 28, 2026
6a79349
fix(git): commit leaves out only the project's own build folders
claude Oct 28, 2026
d7b8593
Merge pull request #1766 from ako/claude/loving-clarke-qun7w5
ako Oct 28, 2026
76e47b0
Merge pull request #1767 from ako/claude/optimistic-fermi-x62bln
ako Oct 28, 2026
58e8346
fix(widgets): read switch arms and statement-head guards in editorCon…
claude Oct 28, 2026
afe48e6
fix(describe): leave out a pluggable widget property it hides at its …
claude Oct 28, 2026
75ee548
fix(microflows): edit an activity replaced by one of the same kind in…
claude Oct 28, 2026
76efadf
docs(microflows): say what a same-kind replace keeps
claude Oct 28, 2026
35741a2
fix(canon): leave the end-of-path marker out of a parallel split belo…
claude Oct 28, 2026
761fab0
fix(modelsdk): give WidgetReturnType.assignableTo and GroupBox.header…
claude Oct 28, 2026
4939d51
fix(git): doctor judges only core.autocrlf — the mendix.* counters ar…
engalar Oct 29, 2026
6ddd5e5
fix(git): the staged-files summary lists what the commit holds, not t…
engalar Oct 29, 2026
4e961b2
feat(git): `git merge` reviews conflicts before they land — report bo…
engalar Oct 29, 2026
f759979
feat(git): per-unit conflict resolution — property-level report (mx d…
engalar Oct 29, 2026
e42dd94
Merge pull request #1675 from ako/main
ako Oct 29, 2026
2dc8aa2
Merge pull request #1770 from ako/claude/loving-clarke-qun7w5
ako Oct 29, 2026
61c38e1
fix(gitignore): ignore the unit-type index under testdata fixtures too
claude Oct 29, 2026
4335dff
fix(layout): an error handler's row reserves the lane under its activity
claude Oct 29, 2026
34d3787
fix(layout): a later @position no longer moves the statements before it
claude Oct 29, 2026
49dec83
fix(lint): MPR008 compares events and type splits
claude Oct 29, 2026
83f22ae
fix(executor): every nested flow body keeps the splice's member guard
claude Oct 29, 2026
8d3089e
fix(executor): type a stored retrieve over an association for a fragment
claude Oct 29, 2026
47ec0e0
fix(canon): store a user task's targeting as UserSource below Mendix …
claude Oct 29, 2026
f9fcc87
fix(canon): write a user task as a Workflows$UserTask below Mendix 10.12
claude Oct 29, 2026
3c69d95
fix(wfmutator): set a user task's targeting whichever key stores it
claude Oct 29, 2026
684a447
fix(executor): gate the user-task features older Mendix cannot store
claude Oct 29, 2026
b47de7e
test(doctype): write user tasks in the Mendix 10 workflow script
claude Oct 29, 2026
ee1a059
test(bug-tests): measure the 1771 user-task shapes on Mendix 10.11
claude Oct 29, 2026
f62863b
ci: add Mendix 11.16.0 to the nightly test matrix
claude Oct 29, 2026
316b482
Merge pull request #1772 from ako/claude/loving-clarke-qun7w5
ako Oct 29, 2026
7382ede
Merge branch 'mendixlabs:main' into main
ako Oct 29, 2026
cad9b08
Merge pull request #1779 from ako/claude/vibrant-knuth-3lhlkd
ako Oct 29, 2026
0377b76
Merge pull request #1677 from ako/main
ako Oct 29, 2026
2788811
fix(git): the git-merge fixtures run git hermetically and show what t…
engalar Oct 30, 2026
a5df7bf
Merge upstream/main: insteadOf-aware doctor, notes-fetch finding, pro…
engalar Oct 30, 2026
69a1fdf
fix(git): the model merge runs mx merge over three project folders, g…
engalar Oct 30, 2026
4fa453f
docs(skills): regenerate the teamserver-git section index after the m…
engalar Oct 30, 2026
6550296
Merge upstream/main: #1791 unit-index naming, #1789 catalog reads, #1…
engalar Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions .claude/skills/mendix/teamserver-git/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ description: "Commit, branch and push a Mendix project in git the way Studio Pro
| 42-55 | Branches: create them on the server |
| 56-101 | Commit from the agent |
| 102-116 | Push the branch and the notes together, and soon |
| 117-129 | Never rewrite or merge model history with git |
| 130-140 | Reading what Studio Pro recorded |
| 141-149 | Checklist |
| 117-138 | Never rewrite or merge model history with git |
| 139-149 | Reading what Studio Pro recorded |
| 150-158 | Checklist |

<!-- /skill-index -->
# Working with Git on a Mendix Team Server Project
Expand Down Expand Up @@ -116,11 +116,20 @@ git push origin <branch> refs/notes/mx_metadata

## Never rewrite or merge model history with git

- **No `git merge`, `rebase` or `cherry-pick` of model changes.** The `.mpr` is
a SQLite file; git cannot merge it, and a textual merge of `mprcontents/`
leaves an index that does not match the files. Studio Pro has a model-aware
merge: **Version Control › Merge Changes Here** (*Merge feature branch* or
*Cherry Pick*). Studio Pro's history on Team Server is linear for that reason.
- **No plain `git merge`, `rebase` or `cherry-pick` of model changes.** The
`.mpr` is a SQLite file; git cannot merge it (every two-sided model change
is a binary conflict), and a textual merge of `mprcontents/` leaves an
index that does not match the files. Model-aware merging exists in two
forms: **`mxcli git merge <ref>`** from the command line (it hands the
conflict to `mx merge` over three project folders — Studio Pro's own
engine, Linux devcontainers included — and commits the resolved model as a
normal merge commit with the note), and **Version
Control › Merge Changes Here** in Studio Pro (*Merge feature branch* or
*Cherry Pick*) — which is also where the conflicts mx cannot auto-resolve
go. A conflict `mxcli git merge` cannot resolve — and an engine failure —
aborts the merge cleanly; nothing is left half-done.
Studio Pro's history on Team Server is linear for a reason: do not "fix"
a conflicted model merge by hand-editing files.
- **No `--amend` or force-push of a pushed commit.** Before pushing, an amend is
fine: the `notes.rewriteRef` Studio Pro puts in `.git/config` carries the
note. Re-run `mxcli git note --write` anyway; it is cheap.
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added

- **`mxcli git commit -m … -p app.mpr` — commit the way Studio Pro does** (mendixlabs/mxcli#1669) — Studio Pro's *Commit* is more than `git commit`: it keeps the ContentsHash index in step, stages exactly the files a Mendix repository ships, and attaches the mx_metadata note. The new command is that sequence in one line: mismatched hashes are repaired from the files on disk first (`MISSING` and `ORPHAN` entries have no automatic repair and refuse the commit), everything is staged and the files Studio Pro never commits (`project-settings.user.json`, `*.mpr.lock`, `*.mpr.bak`, and the project's own `.mendix-cache/`, `deployment/`, `theme-cache/`, `.mxcli/` beside the `.mpr` — a folder of the same name further down, such as `resources/deployment/`, is committed) are unstaged again, `git commit` runs with the caller's message and identity, and the mx_metadata note is computed from the new commit and attached, so Studio Pro can version-check the revision and show what changed. `--push` pushes the branch and the notes ref together (`git push` alone loses the note the next time Studio Pro fetches); `--dry-run` reports what it would commit without committing — and without repairing anything, hash drift included, because a dry run writes nothing: it stages into a copy of the index, so what the user had staged is left as it was. The commit is refused while Studio Pro has the project open (`.mpr.lock`) — honouring the same `MXCLI_ALLOW_STUDIO_PRO_OPEN=1` override as every write — and during an unresolved merge, which `git add -A` would otherwise commit with its conflict markers. Docs: "Working Outside Studio Pro" › *One commit, all the steps*.
- **`mxcli git merge <ref>` — model-aware merging from the command line** (mendixlabs/mxcli#1669) — `git merge` cannot merge Mendix models: the `.mpr` is SQLite and every `.mxunit` is BSON, so two sides changing the model always meet a binary `CONFLICT (content)` (measured in the git lab: both files, every time). Studio Pro resolves that with a model-aware merge, and the same engine ships as a command — `mx merge BASE MINE THEIRS` over three project folders, which runs on Linux devcontainers too (the older `mx git-merge` file form is Windows-bound). `mxcli git merge <ref>` runs `git merge` first (a merge git resolves itself is annotated like `mxcli git commit`; a merge stopped on text conflicts resumes once those are resolved and staged), and on a model-file conflict checks the base and theirs revisions out into temporary worktrees and hands the three project folders to the engine, mx resolved for the project's Mendix version (PATH, the mxcli cache, the Studio Pro installation): everything the engine auto-resolves is staged, hash-checked and committed as the normal two-parent merge commit with the mx_metadata note — and the engine owns the `.mpr`, so a unit one side added while the other changed existing ones is kept, not dropped; a conflict the engine reports as `ManualResolutionRequired` (exit 2) is a review step, never a silent choice: the merge aborts leaving the working tree exactly as before, and both sides' changes are printed unit by unit at property level (from `mx diff`), with a plan template (`<mpr>.merge-plan.json`, never staged by `mxcli git commit`) beside the project — the human re-runs with `--plan <file>` to resolve **per unit** (each conflicted unit takes `ours` or `theirs`, the `.mpr` index is repaired from the mixed files; modified-on-both units only, added/deleted/moved goes to Studio Pro), or with `--ours`/`--theirs` to take one side of every conflicted unit — hash-gated: when the sides' document sets differ (one side added or deleted a unit) the commit is refused and the merge aborted, because a whole side would orphan the other side's documents — or resolves in Studio Pro (*Version Control › Merge Changes Here*), which remains the tool for mixed resolutions; any other engine exit (its 129, an mx that will not start) is reported as the engine failing and the merge is aborted cleanly, never steered into a decision. Non-model conflicts (text sources) are left in place like plain git: resolve them, `git add` them, re-run the command. Refused while Studio Pro has the project open. Docs: "Working Outside Studio Pro" › *Merging branches*.
- **`mxcli git doctor [-p app.mpr] [--fix]` — audit a repository for everything a plain-git history misses, and repair it** (mendixlabs/mxcli#1669) — a repository committed only with git drifts from what Studio Pro expects in four ways, each invisible on its own: the local git config Studio Pro writes is absent (`core.autocrlf=False` keeps a checkout from rewriting line endings inside `.mxunit` files on Windows; `mendix.commits-since-gc` and `mendix.lineEndingResetDone` are its own bookkeeping), the remote is SSH which Studio Pro cannot use (HTTPS only), commits have no note under `refs/notes/mx_metadata` (history shows `(unknown)`, the version check fails), and a malformed note Studio Pro cannot read at all. `doctor` reports all four in one read-only pass and exits 1 while an issue remains, so it can gate CI. `--fix` sets the config keys, rewrites SSH remote URLs (`git@host:org/app.git`, `ssh://…`) to HTTPS — judged as configured, so a `url.<base>.insteadOf` rule in the user's git config (https → `git@` is a common one) is reported rather than "repaired" on every run — and backfills notes: computed from the model with `-p` (the same engine `git note` uses), or a template note with a `--version` ModelerVersion where the model at a commit cannot be read (MPR v1 history, a revision without the `.mpr`); with neither, the newest valid note in history supplies the version. Notes Studio Pro wrote are never touched, with or without `--fix`; `--fix` does not push. A clone whose notes ref lacks the remote's notes — `git clone` never fetches `refs/notes/*`, so every fresh clone and CI checkout — is reported as exactly that, with the fetch command, rather than as a history of unannotated commits; `--fix` fetches the notes first, as a fast-forward only. Docs: "Working Outside Studio Pro" › *Auditing a repository*.

### Changed
Expand Down
35 changes: 18 additions & 17 deletions cmd/mxcli/cmd_git_commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,22 @@ func commitRun(mprPath, message string, push, dryRun bool, out io.Writer) error
fmt.Fprintln(out, "nothing to commit, working tree clean")
return nil
}
fmt.Fprintf(out, "Staged %d file(s):\n", len(staged)-len(junk))
kept := staged
if len(kept) > 10 {
kept = kept[:10]
kept := make([]string, 0, len(staged)-len(junk))
for _, f := range staged {
if !isJunkPath(f, projDir) {
kept = append(kept, f)
}
}
for _, f := range kept {
fmt.Fprintf(out, "Staged %d file(s):\n", len(kept))
shown := kept
if len(shown) > 10 {
shown = shown[:10]
}
for _, f := range shown {
fmt.Fprintf(out, " %s\n", f)
}
if len(staged)-len(junk) > 10 {
fmt.Fprintf(out, " … and %d more\n", len(staged)-len(junk)-10)
if len(kept) > 10 {
fmt.Fprintf(out, " … and %d more\n", len(kept)-10)
}

if dryRun {
Expand All @@ -184,16 +190,7 @@ func commitRun(mprPath, message string, push, dryRun bool, out io.Writer) error
return fmt.Errorf("committed %s, but attaching the note failed (%v) — run 'mxcli git note -p %s --write' to attach it", shortCommit(head), err, mprPath)
}

if push {
if branch == "" {
return errors.New("detached HEAD; cannot push — check out a branch and push manually")
}
if _, err := gitOutIn(root, nil, "push", "origin", branch, mxMetadataRef); err != nil {
return fmt.Errorf("push %s and %s: %w", branch, mxMetadataRef, err)
}
fmt.Fprintf(out, "Pushed %s and %s to origin.\n", branch, mxMetadataRef)
}
return nil
return pushBranchAndNotes(out, root, branch, push)
}

// indexCopy copies the repository's index to a temporary file, for a
Expand Down Expand Up @@ -264,6 +261,10 @@ func isJunkPath(rel, projDir string) bool {
return true
case strings.HasSuffix(strings.ToLower(base), ".mpr.lock"), strings.HasSuffix(strings.ToLower(base), ".mpr.bak"):
return true
// `mxcli git merge` writes the plan template beside the .mpr for the
// human to edit; it is working material, never project content.
case strings.HasSuffix(strings.ToLower(base), ".merge-plan.json"):
return true
}
inProject := f
if projDir != "." && projDir != "" {
Expand Down
5 changes: 3 additions & 2 deletions cmd/mxcli/cmd_git_doctor.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ var gitDoctorCmd = &cobra.Command{

Checked:
1. Local git config: core.autocrlf=False (a checkout must not rewrite line
endings inside .mxunit files), mendix.commits-since-gc and
mendix.lineEndingResetDone (Studio Pro's own bookkeeping). --fix sets them.
endings inside .mxunit files; --fix rewrites any other value), and the
mendix.* keys (Studio Pro's own bookkeeping) backfilled when missing —
a value Studio Pro wrote stays.
2. The remote URL, as configured. Studio Pro can only use HTTPS; an SSH
remote (git@host:org/app.git or ssh://…) is rewritten to HTTPS by --fix.
Other non-HTTPS URLs are reported without being changed. A
Expand Down
Loading
Loading