Branching and change requests
Create branches, commit Resource revisions, and open, merge, or close change requests with the Istari Digital Python client. Use this when branching and merging are part of an automated pipeline — for example, committing simulation output to a branch and opening a change request for review.
For the conceptual model (Resource versions vs System branches), see Version control. For the same flows in the web app, see Branches.
Prerequisites
- A configured
Client— see SDK setup. - Editor (or above) on the target System.
Getting a System and its branches
Branch operations live on the System object. Every System starts with a baseline branch:
system = client.get_system("26db98...") # your system ID
baseline = system.get_branch("baseline")
branches = system.list_branches() # all branches except baseline
Creating a branch
Create a new branch off any existing branch to isolate the changes you're making:
v2 = system.create_branch("v2", from_branch=baseline)
The add_to_branch helper commits to working branches; to update baseline, merge a change request into it as shown below.
Committing Resources to a branch
Upload each file as a model, then commit its revision to the branch. You can commit several revisions (and Subsystems) in a single commit. add_model is deprecated in 13.1.9 and warns. It still returns the Model whose .revision add_to_branch takes. The same upload on V3Client is create_resource.
render = client.add_model("renders/back.png")
bom = client.add_model("bill_of_materials.json")
v2 = system.add_to_branch(v2, revisions=[render.revision, bom.revision])
To remove tracked files from a branch, use system.remove_from_branch() with the same arguments. Each call to add_to_branch / remove_from_branch creates one commit:
for commit in system.list_branch_history(v2): # newest first, like `git log`
print(commit.snapshot_id, commit.created)
Creating a change request
Merge by creating a change request from your working branch (the source) into the branch you want to update (the target):
from istari_digital_client import ChangeRequestCreateRequest
response = client.create_change_request(
system_id=system.id,
change_request_create_request=ChangeRequestCreateRequest(
source_tag_id=v2.id,
target_tag_id=baseline.id,
title="Move v2 to baseline",
description="Added the renders and bill of materials",
),
)
change_request = response.actual_instance # an OpenChangeRequestResponse
print(change_request.change_request_id, change_request.status) # ... OPEN
Reviewing the changes
Get high-level counts first:
summary = client.change_request_change_summary(
system_id=system.id,
change_request_id=change_request.change_request_id,
)
print(f"{summary.added_count} added, {summary.removed_count} removed, "
f"{summary.changed_count} changed")
Then page through the full delta:
diff_page = client.change_request_changes(
system_id=system.id,
change_request_id=change_request.change_request_id,
)
for item in diff_page.items:
diff = item.actual_instance # a resource diff or a subsystem diff
print(diff.diff_type, diff.name)
You can filter the delta with component_type= (RESOURCE, SUBSYSTEM, or ALL) and change_types= (a list of ADDED, REMOVED, CHANGED), using the ChangeRequestComponentType and ChangeRequestDiffType enums. If has_more is true, pass next_cursor back as cursor= and the page's head_pair_token back as x_head_pair_token= so the next page stays on the same pair of branch heads.
Merging the change request
from istari_digital_client import ChangeRequestMergeRequest
merged = client.merge_change_request(
system_id=system.id,
change_request_id=change_request.change_request_id,
change_request_merge_request=ChangeRequestMergeRequest(
comment="Approved and merged",
),
).actual_instance
print(merged.status) # MERGED
To close a change request without merging it, call update_change_request with status="CLOSED". The body is a full replacement: omitting title or description clears that field, so send the current values back when you only want to change the status. MERGED is not a valid status here — merging stays on merge_change_request. status="OPEN" reopens a closed request, with the same replacement rule.
from istari_digital_client import ChangeRequestUpdateRequest
closed = client.update_change_request(
system_id=system.id,
change_request_id=change_request.change_request_id,
change_request_update_request=ChangeRequestUpdateRequest(
status="CLOSED",
title=change_request.title,
description=change_request.description,
comment="Rejected",
),
).actual_instance
print(closed.status) # CLOSED
End-to-end example
from istari_digital_client import (
ChangeRequestCreateRequest,
ChangeRequestMergeRequest,
Client,
Configuration,
)
client = Client(Configuration(
digital_api_url="https://api.your-instance.istari.app",
identity_service_secret_file="/absolute/path/to/key.json",
identity_service_enabled=True,
))
system = client.get_system("26db98...")
baseline = system.get_branch("baseline")
v2 = system.create_branch("v2", from_branch=baseline)
bom = client.add_model("bill_of_materials.json")
v2 = system.add_to_branch(v2, revisions=[bom.revision])
change_request = client.create_change_request(
system_id=system.id,
change_request_create_request=ChangeRequestCreateRequest(
source_tag_id=v2.id,
target_tag_id=baseline.id,
title="Move v2 to baseline",
),
).actual_instance
summary = client.change_request_change_summary(
system_id=system.id,
change_request_id=change_request.change_request_id,
)
print(f"{summary.added_count} added, {summary.removed_count} removed, "
f"{summary.changed_count} changed")
client.merge_change_request(
system_id=system.id,
change_request_id=change_request.change_request_id,
change_request_merge_request=ChangeRequestMergeRequest(comment="LGTM"),
)
Related reference
- Change requests — parameter tables for create, list, diff, merge, and close.
Systembranching methods —create_branch,add_to_branch,list_branch_history, and related helpers.- Systems API — System, configuration, snapshot, and folder methods on
Client.