5.2 KiB
Embedding Commit History in IFC Files
A survey of IFC mechanisms for storing git commit metadata.
1. IfcOwnerHistory — The Native Mechanism
Every IfcRoot-derived entity (walls, spaces, products, etc.) carries an optional IfcOwnerHistory attribute. It is the closest thing IFC has to built-in change tracking.
Fields:
| Field | Type | Notes |
|---|---|---|
OwningUser |
IfcPersonAndOrganization |
Who created the element |
OwningApplication |
IfcApplication |
Software used |
State |
IfcStateEnum |
READWRITE, READONLY, LOCKED |
ChangeAction |
IfcChangeActionEnum |
ADDED, MODIFIED, DELETED, NOCHANGE |
LastModifiedDate |
IfcTimeStamp |
Unix timestamp |
LastModifyingUser |
IfcPersonAndOrganization |
|
LastModifyingApplication |
IfcApplication |
|
CreationDate |
IfcTimeStamp |
Unix timestamp |
Raw IFC line from samples/duplex.ifc:
#33=IFCOWNERHISTORY(#32,#2,$,.NOCHANGE.,$,$,$,0);
Limitations:
- Only the current state — no history chain
ChangeActionis a coarse enum; no room for a commit hash, message, or branchIfcApplication.Versionis a short string, not designed for structured data- One record per element; previous owners are lost on update
Verdict: Good for standard compliance and timestamping. Not sufficient alone for git metadata.
2. IfcPropertySet — The Recommended Extension Point
Custom property sets (Pset_*) are the standard IFC way to attach arbitrary key-value metadata to any IfcObject. They survive round-trips through most IFC-aware tools (unknown Psets are ignored, not discarded).
Proposed schema — Pset_GitCommit:
| Property | Type | Example |
|---|---|---|
CommitHash |
IfcLabel |
a1b2c3d4f5e6c7b8 |
CommitMessage |
IfcText |
Fix wall thickness |
CommitAuthor |
IfcLabel |
alice <alice@example.com> |
CommitDate |
IfcLabel |
2026-03-24T14:30:00Z |
CommitBranch |
IfcLabel |
main |
OperationName |
IfcLabel |
Modify |
ifcopenshell snippet:
pset = ifcopenshell.api.pset.add_pset(model, product=element, name="Pset_GitCommit")
ifcopenshell.api.pset.edit_pset(model, pset=pset, properties={
"CommitHash": commit_hash,
"CommitMessage": commit_message,
"CommitAuthor": commit_author,
"CommitDate": commit_date,
"CommitBranch": branch,
})
Reading back:
for rel in element.IsDefinedBy or []:
if rel.is_a("IfcRelDefinesByProperties"):
pset = rel.RelatingPropertyDefinition
if pset.Name == "Pset_GitCommit":
props = {p.Name: p.NominalValue.wrappedValue for p in pset.HasProperties}
Verdict: Best fit for per-element traceability. Flexible, queryable, spec-compliant.
3. IfcDocumentInformation — For Linking to External Commits
IfcDocumentInformation + IfcRelAssociatesDocument lets you attach a document reference (URL, identifier, description) to any IfcRoot entity. It is designed for spec sheets and drawings but can carry a git commit URL.
doc = ifcopenshell.api.document.add_information(model)
ifcopenshell.api.document.edit_information(model, information=doc, attributes={
"Identification": commit_hash[:8],
"Name": commit_message,
"Location": f"https://gitaec.org/rvba/ifc-commit/commit/{commit_hash}",
})
ref = ifcopenshell.api.document.add_reference(model, information=doc)
ifcopenshell.api.document.assign_document(model, products=[element], document=ref)
Verdict: Useful if you want to link elements back to a hosted commit URL. More verbose than a Pset. Better for file-level "source revision" than per-element tracking.
4. IfcApplication — File-Level Commit Stamp
IfcApplication is referenced by every IfcOwnerHistory. Its Version field can carry the current commit hash as a lightweight file-level stamp.
app = ifcopenshell.api.owner.add_application(model, ...)
ifcopenshell.api.owner.edit_application(model, application=app, attributes={
"ApplicationIdentifier": "ifc-commit",
"Version": commit_hash, # e.g. "a1b2c3d4"
"Name": "ifc-commit",
})
Verdict: Zero overhead, but limited to one hash per file. Good as a quick "what commit produced this file" marker.
5. Comparison
| Mechanism | Granularity | Stores hash/message | IFC compliance | Overhead |
|---|---|---|---|---|
IfcOwnerHistory |
per-element | No | Native | Minimal |
Pset_GitCommit |
per-element | Yes (all fields) | Standard extension | Medium |
IfcDocumentInformation |
per-element | Yes (via Location) | Standard | High |
IfcApplication.Version |
per-file | Hash only | Native | Minimal |
6. Recommendation
A two-layer approach:
-
File level — Set
IfcApplication.Versionto the commit hash. Every tool that readsIfcOwnerHistorywill expose this. -
Element level — On elements touched by an operation (extract, merge, replace), write a
Pset_GitCommitproperty set with the full commit metadata. UpdateIfcOwnerHistory.ChangeActiontoADDEDorMODIFIEDaccordingly.
This keeps standard IFC compliance intact while making full git provenance queryable directly from the model.