work publish is the Copado Commit for local Git work. It:
- Detects metadata changes on the feature branch (including nested components and permission sets).
- Applies Copado environment-variable and YAML replacements when the story has them.
- Pushes the feature branch, registers the commits on the User Story and updates the dev org branch.
A plain git push does none of that. You must still be on feature/US-XXXXXXX with a clean tree.
agentia cicd work publish
Metadata detection usually covers this example without extra flags. For the Account Tag / Sales Team story, the nested-detection step looks like this:
Detecting nested metadata changes... done
Permission parents (kept in the change list):
PermissionSet:Sales_Team
Nested metadata: CustomField:Account.Phone,
CustomField:Account.Tag__c, CustomObject:Account
Retrieve only (nested Profile and PermissionSet metadata):
CustomField:Account.Phone
CustomField:Account.Tag__c
CustomObject:Account
Read those three lists before you submit:
| List | In this example | Meaning |
|---|
| Permission parents (kept in the change list) | PermissionSet:Sales_Team | The permission set (or profile) file stays on the commit. Copado needs that parent to apply the access changes. |
| Nested metadata | CustomField:Account.Phone, CustomField:Account.Tag__c, CustomObject:Account | Members that actually changed inside a parent file — here, object and field access on Sales Team. |
| Retrieve only | The same three names | Not deployed as their own components. Copado retrieves them from the org and applies only the permission set (or profile) access. Phone is not redeployed; Tag still deploys from its own field file if you committed it. |
Other lines appear when they apply: Nested parents (a non-permission parent whose file changed only inside nested blocks) and Nested metadata deleted (a nested member removed from a parent). Each line is left out when its list is empty.
Nested metadata and permissions
Salesforce often stores several Copado components in one file (a permission set, a profile, a custom object, a workflow). If Copado took the whole file, the promotion would carry members another story owns. Publish diffs the branch and registers what actually changed:
| What you changed | What Copado receives |
|---|
New nested files such as Account.Tag__c or TagValidation | Those components (not the entire Account object, unless you changed object-level fields) |
| A new permission set, or you ask for the whole file | Full metadata — the complete permission set deploys |
Only access inside an existing permission set or profile (for example Phone or Tag__c FLS) | The parent file is committed; the named permissions are Retrieve Only, so Copado applies access without redeploying those fields or classes |
| A nested member removed from a parent file (not a permission revoke) | A delete of that member |
| A field permission removed from a permission set | Still Retrieve Only — revoking FLS does not delete the field |
If auto-detection gets it wrong, override it with flags on that publish only. This is like picking nested items, permissions or full metadata by hand in the Copado Commit experience.
agentia cicd work publish --permissions CustomField:Account.Tag__c
agentia cicd work publish --full-metadata PermissionSet:Sales_Team
agentia cicd work publish --skip-nested-metadata-detection
Environment-variable and YAML replacements
If the User Story has Copado replacement rules, publish applies them to the files this branch added or changed, then commits the result (the message ends with copado replacements) before registering. You don't run the replacement tools yourself. Delete-only commits have nothing to rewrite, so replacements are skipped.
Deletes
To remove nested metadata, delete the file in Git, commit and publish:
git rm force-app/main/default/objects/Account/validationRules/TagValidation.validationRule-meta.xml
git commit -m "US-XXXXXXX: remove TagValidation"
agentia cicd work publish
Publish registers the member as deleted, but side effects — like a deleted field affecting all the layouts of its object — are not added to the commit automatically. Retrieve the related metadata of the object and commit it too. That's the usual way to work with Salesforce and Git; Copado cloud commits can detect these cascade deletions, which would be too intrusive to do locally.