Skip to main content
Version: 2026.09

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)
note

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"),
)
  • Change requests — parameter tables for create, list, diff, merge, and close.
  • System branching methods — create_branch, add_to_branch, list_branch_history, and related helpers.
  • Systems API — System, configuration, snapshot, and folder methods on Client.