Jazz Forum Welcome to the Jazz Community Forum Connect and collaborate with IBM Engineering experts and users

Reverse the changeset through API

 Hi,

Am trying to reverse the changeset programmatically,but couldn't get through as not sure the actual arguments to pass to commit operation.Have followed the link to some extent but couldn't figure the working code.Can you please have a look on below code and let me know where I am wrong.It would be great if you able to share working version.

IWorkspaceManager workspaceManager = SCMPlatform
.getWorkspaceManager(teamRepository);
IWorkspaceSearchCriteria streamSearchCriteria = WorkspaceSearchCriteria.FACTORY
.newInstance();
streamSearchCriteria.setKind(IWorkspaceSearchCriteria.WORKSPACES);
streamSearchCriteria.setPartialName("TEST_CHANGE_REVERSE");
List<IWorkspaceHandle> sourceStreamList = workspaceManager
.findWorkspaces(streamSearchCriteria, Integer.MAX_VALUE,
null);
System.out.println("No of Workspaces---->"+sourceStreamList.size());
IWorkspaceConnection wsConn = workspaceManager
.getWorkspaceConnection(sourceStreamList.get(0), null);

IConfigurationOpFactory opFactory = wsConn.configurationOpFactory();

IWorkItem taskWi = workItemClient.findWorkItemById(
Integer.parseInt("134293"), IWorkItem.FULL_PROFILE, null);
IItemReference linkTarget = IReferenceFactory.INSTANCE
.createReferenceToItem(taskWi);
ILinkQueryPage changeSets = linkManager.findLinksByTarget(
WorkItemLinkTypes.CHANGE_SET, linkTarget,
new NullProgressMonitor());
ILinkCollection linkCollection = changeSets.getLinks();
for (ILink iLink : linkCollection) {
IChangeSetHandle changeSetHandle = (IChangeSetHandle) iLink
.getSourceRef().resolve();

String csComment = iLink.getSourceRef().getComment();
System.out.println("Comment--->" + csComment);
IItemManager itemManager = teamRepository.itemManager();
IChangeSet changeset = (IChangeSet) itemManager
.fetchCompleteItem(changeSetHandle,
IItemManager.DEFAULT, null);
for (Object chng : changeset.changes()) {
Change change = (Change) chng;
if (change.afterState() instanceof IVersionableHandle) 
//opFactory.revert(change.beforeState());
wsConn.commit(changeSetHandle, Collections.singleton(opFactory.revert(change.afterState())), null);
}

0 votes

Comments

What error is preventing your solution from working? Could you provide the stack trace and error message?


Here are a few guesses:
  1. you're operating on a random workspace. It may not contain the versionable you're trying to modify.
  2. whenever you're dealing with the before/after state of an IChange it's worth remembering that they can be null for an add or delete. If you're getting a null pointer exception, that could be the cause. 
  3. since you're grabbing a change set from a work item, it's possible that the change set doesn't exist in the workspace you're running commit on. 
  4. you can only commit to active change sets, so make sure that the change set is active before running commit. 

Am sorry for delay,Getting below error when tried revert() on afterchange.Am not sure how beforeState() and afterState() works as struggling to find documentation for API Change class.

com.ibm.team.scm.common.CompletedChangeSetException
: Changes can only be checked into a new change set or a change set that is active in a workspace.
at com.ibm.team.scm.service.internal.utils.ChangeSetUtils$2.createException(
ChangeSetUtils.java:73)

t com.ibm.team.scm.service.internal.utils.IExceptionFactory$AbstractExceptionFactory.createException(
IExceptionFactory.java:35)
at com.ibm.team.scm.service.internal.operations.commit.CommitChangeTracker.determineTargetChangeSets(
CommitChangeTracker.java:182)
at com.ibm.team.scm.service.internal.operations.commit.CommitOperation.run(
CommitOperation.java:351)
at com.ibm.team.scm.service.internal.ScmService$22.run(
ScmService.java:1215)

my comments to the points you outlined.

  1. you're operating... >>>>Have ensured random workspace has the change wanted to rollback.In fact created random workspace from steam that has changes delivered.
  2. whenever you're ...>>>Am using Change(Not IChange) class here and have a null check in place
  3. since you're grabbing a change ... >> relevant to 1,Have ensured all changes included in workspace
  4. you can only commit to active change sets... >> May be I'm not fully certain here(not sure what active changeset mean) ,but not disabled any changes implemented from workitem on the object in RTC stream

 Thanks Evan The fourth assumption is relevant to my issue here,Could reverse the change if changeset is active(new changeset check into repo workspace,but not delivered to stream),but I wanted to reverse closed changesets and it would be helpful if you guide me how to reopen the closed changeset or other better ways.

 Thanks David and Evan,Am all set .It's working now


Accepted answer

Permanent link
As David suggests, you should use IWorkspaceConnection#createChangeSet() to create a new change set, then commit changes into that.

An active change set is one that you can commit to. It's shown without a green check-mark in the UI. When a change set is completed/closed, it is no longer active and cannot be committed to. Completing a change set is done automatically on delivery.

If there are other active change sets in the IWorkspace that modify the same item, your commit will fail. You can use IWorkspaceConnection#activeChangeSets() to get a listing of the active change sets and iterate over the items that they modify (again, be aware that IChange can return null for many of the fields, so include a null check).

If you have created the new workspace from the stream as part of your operation, then there won't be any active change sets, so you can skip the previous paragraph. ;)

suresh k selected this answer as the correct answer

0 votes


One other answer

Permanent link
Suresh, you cannot re-open a closed change set. You would need to check-in the reversal changes into a new change.
A new change set can be created using:
IChangeSetHandle cset = wsConn.createChangeSet(component, progress.newChild(25));

Then you can deliver this change set to the stream to reverse the changes (the other option is to discard the change set from the stream, although if changes are build on top of that one, it might not always be possible (or easy) to discard that one change set).

2 votes

Comments

 Hi Evan,David,A follow up question:


I couldn't retain the changes implemented before and after the changeset wanted to reverse.If I choosen beforeState() all the changes to the state before change selected to reverse being deleted and afterState() keep changes upto the change wanted to reverse and remaining will get deleted.

e.g : sample.txt has multiple changes C1,C2 and C3 applied on the sequence .C2 reverse wtih beforeState() keep only C1 on sample.txt and retain C1,C2 if we choosed afterState().

Wanted to retain both C1 and C3 post C2 reverse .Would like to know,If there is options to support this ?

What you said is true. If you replace with the start/end states of a change set, you will be wiping out changes that came after that change set. Since a change set represents a transition between two states, to really 'reverse' something, you want to merge in the semantic changes, or delta, between the end and start states; similar to trying to merge patch 'hunks' into your workspace.  This is equivalent to trying to accept a change set with a gap, except in that case we're trying to apply the delta between a start state and an end state of a change set (whereas in this case you want the reverse of that).

The IWorkspaceConnection.revert() method you were using is used to 'revert' a versionable to an older state (and not merge in a semantic reversal). In our UI the user can click on a change set and click "Reverse" which will create a patch in the Pending Changes view where the user may have to manually merge in the patch.

Unfortunately there would be no way write an algorithm to reliably automate this since in some cases ambiguity/conflicts can arise which would require human intervention.
(see the next comment for an example)

Here are 3 change sets:

CS1 = Add methodB()
   Content of afterstate:
      public void methodA() {...}
      public void methodB() {...}
      public void methodC() {...}

CS2 = Modify methodB()
   Content of afterstate:
      public void methodA() {...}
      public void methodB() {...some changes...}
      public void methodC() {...}

CS3 = Delete methodB
   Content of afterstate:
      public void methodA() {...}
      public void methodC() {...}

Now if you want to reverse CS2, it means undoing the changes in methodB. But the final configuration in this example is at CS3, in which methodB does not even exist. An algorithm would not know how to merge in the 'undoing of the changes in methodB'. Due to this conflict, a user would manually have to decide what to do. (Perhaps methodB was renamed or moved somewhere else... in that case, a user might be able to track that down and correctly apply the reversal)

 Thanks David for the confirmation,Will decide next course of actions based on this info to conclude RTC extention for change reverse

Your answer

Register or log in to post your answer.

Dashboards and work items are no longer publicly available, so some links may be invalid. We now provide similar information through other means. Learn more here.

Search context
Follow this question

By Email: 

Once you sign in you will be able to subscribe for any updates here.

By RSS:

Answers
Answers and Comments
Question details
× 10,927

Question asked: Feb 13 '15, 7:10 a.m.

Question was seen: 3,912 times

Last updated: Feb 26 '15, 1:52 a.m.

Confirmation Cancel Confirm