Jump to content

Working in parent repo sometimes results in empty commits in wxlinked sub-repos


Mikael Kalms

Recommended Posts

Hi,

we have a repository which the entire team works within, and then we have 5 sub-repos that are wxlinked within the parent repository. People are normally working within the parent repository only -- changes within the sub-repos are very rare.

 

For some reason which we do not understand, when people work normally in the parent repository, corresponding branches are being created with empty changesets within the sub-repos. This pollutes history within the sub-repos, causes confusion ("what are these extra 5 items in this merge?"), and makes the Incoming Changes view fail (it doesn't handle merges in sub-repos).

 

If possible, we would like to find out why these empty changesets & extra branches appear in the sub-repos -- and, if possible, stop them from appearing in the future.

 

I'm not sure exactly about the conditions under which this happens. I find it difficult to reproduce on my own, when there is no activity from others in the repository.

For example, I tried this just now, and it did not happen: I created a child branch, checked in a change into that child branch, merged up from child to parent, checked in a change into the parent branch, merged from parent to child. I think it is much more likely to show up if there is concurrent activity from users. (Not necessarily two operations running at the same time, but perhaps two branches need to exist with partial overlap in time.)

 

One thing that I have noticed is that whenever this happens, all 5 sub-repos will end up with branches & blank commits, and during subsequent merges all 5 wxlinks will then get updated. If I look back through history there doesn't seem to be any cases where 1, 2, 3 or 4 sub-repos are affected; it's either all or nothing.

If I look at the Branch Explorer within one of these sub-repos, it becomes evident that the empty changesets are strictly related to merge operations (see attached image).

 

 

To put some numbers on this,

there are ~20 developers working within the parent repository.

Between Feb 11th and today there have been about 650 branches in the parent repository, and about 430 branches in each of those sub-repos (out of which 99% are unintentional and contain empty changesets).

empty_changesets.png

Link to comment
Share on other sites

Hi,

The main reason for having an empty changeset: 

- You created a "/main/task001" branch including some changes in your Xlinked repo (some other changes may belong to the parent repo).

- You perform the same changes in your Xlinked repo but this time in the "/main" branch.

- You merge "/main/task001" into "/main" and checkin the changes.

1) If you review the merge result changeset in the parent repo yo will see the merged file revisions.

2) If you review the merge result changeset in the Xlinked repo, the changeset is empty. There was no file revisions to merge in the Xlinked repo because they were already existing on the main branch.

There may be some other scenarios for some empty changesets but this is the most common scenario.

NOTE: Not sure how this workflow can make the "Incoming changes" to fail. This problem happens when the Xlink is not pointing to the last (and a merge is necessary inside the Xlink).

In my example, the Xlink is automatically updated to the last changeset after the merge no merge should be needed in the Xlinked repo when you try to update your workspace via "Incoming changes" view.

Regards,

Carlos.

Link to comment
Share on other sites

What you describe does not match my experience.

 

1. I created a "/main/task001" branch in my parent repo.

2. I made changes in my parent repo.

3. I probably merged from "/main" to "/main/task001" while working in my parent repo. At this point, sometimes I see updates to the xlinked sub-repositories.

4. I was done with my task, so I merged from "/main/task001" to "/main" in my parent repo. At this point, sometimes I see updates to the xlinked sub-repositories.

 

I never made any intentional changes to anything in a sub-repo. This is still resulting in new branches & changesets within sub-repos.

Link to comment
Share on other sites

Hi,

1) When you create a task branch and then checkout a file belonging to the Xlinked repo, a task branch is also created in the XLinked repo.

2) Then, all the changes you perform in the parent repo belonging to the XLinked repo will be propageted to the Xlinked repo creating new changesets in the branch created on step 1.

3) Finally ehen you merge the branch in the parent repo, the same merge will happen in the Xlinked repo. If the changes merged in the XLinked repo already exist on the parent branch, an empty changeset will be created (nothing is merged).

Regards,

Carlos.

Link to comment
Share on other sites

Carlos, you misunderstand me.

What you describe above makes total sense. However, my situation is different: I never change any files that belong to the Xlinked repo, yet Plastic (sometimes, not always) creates commits within the xlinked repo. This seems to happen either in none of the  xlinked repos, or in all 5 xlinked repos - never 1,2,3 or 4 of them.

I do not have a good repro case for this either; I suspect it is something that happens when many people are working concurrently (and make good use of branches) within the same main repository.

Perhaps our main repo and/or sub-repos have ended up in a bad state? I do not know.

Link to comment
Share on other sites

  • 2 weeks later...

Hi Mikael,

Sorry for the dealy. If the task branch is created in the Xlinked repo, at some point some items belonging to the Xlink should have been checked-out.

Are there all the commits created in the Xlinked repo empty? Or only the merge result of the task branches? We can arrange a meeting to take a look on your setup and try to understand what's happening.

Regards,

Carlos.

 

Link to comment
Share on other sites

@M-Pixel I have tried following the repro steps that you posted in the Uservoice to see whether it really is the same problem as I have been seeing. However, from what I can tell, the "good" and the "bad" case in the uservoice are identical procedures. There's a numbering mistake in the "bad" case and the wording for the xlink creation step is different -- but, again, I can't tell any functional difference between "good" and "bad". Can you please clarify this?

Link to comment
Share on other sites

Okay, I have a short repro case of my problem (which may or may not be related to M-Pixel's problem).

 

It involves concurrent branches. When someone changes something within a wxlinked repo on one task branch, and then merges that up to /main, then, under certain circumstances, this results -- a couple of steps further away -- in a merge operation from /main to another task branch resulting in a wxlink update _and_ an empty task branch in the wxlinked repo. This keeps perpetuating itself as long as there are overlapping task branches.

 

Here is the first situation where it becomes obvious that there is a problem:

Screenshot 1 shows, that I am on /main/A2_2_task003, with no local changes. I am about to merge from /main to my branch, using the "Merge from this branch..." feature.

Screenshot 2 shows, that the pending merge is about to update the cset for the wxlink. It is also going to change the branch expansion rule, despite there being no pending changes listed within the wxlinked repo.

Screenshot 3 shows, that an additional branch has been created within the wxlinked repo. This branch is created when I start the "Merge from this branch..." operation.

 

If I undo the merge changes, and delete the additional branch within the wxlinked repo, then I can recreate the problem over again.

 

I will provide a snapshot of the two test repos to Codice via a support ticket.

Screenshot 1.png

Screenshot 2.png

Screenshot 3.png

Link to comment
Share on other sites

8 hours ago, Mikael Kalms said:

... from what I can tell, the "good" and the "bad" case in the uservoice are identical procedures...

Oops!  Good catch.  The post has been fixed.  The difference is merge vs merge-to.  I've consistently seen this behavior when doing merge-to, but not from regular merges.  Is anybody on your team using the merge-to feature?

Sometimes I do notice xlink appear in normal merges, but if no changes were made, then the diff window shows that the target changeset is the same and only other metadata is different (such as addition of an expansion rule).  In cases like that, the XLink does not receive a new commit.  If I don't like the expansion rule that was automatically added, I just go to the workspace explorer and change it before committing (while the merge is pending).

Link to comment
Share on other sites

Hi Mikael,

- The last changeset of the "/main" branch includes a change on the Xlink target. It's not a change on any file belonging to the Xlink but an edition on the XLink target changeset.

- When you run the merge from "/main" to "/main/A2_2_taskk03", only the file conflicts appear in the merge panel and there are not any file revisions belonging to the Xlink in the merge. So you may expect that no merge operation will be necessary on the XLinked repo.

- The reason why the merge operation happens on the Xlinked repo is because the edition on the Xlink target is actually a change that needs to be merged. The fact that the merge result changeset is empty confirms that there was not any file revision merged in this operation but because the only change to be merged is the edition on the Xlink target.

- In summary: When you initially merged "/main/A2_1_task001" to "/main", you are not merging any change in the "/B2/foo2.txt" (becasue this change already exist on main from a previous merge), but also notice that you are actually merging the edition on the Xlink target. And this change in the Xlink target is also merged later from "/main" to "/main/A2_2_taskk03".


?name=inline1976076701.png



Regards,
Carlos.

Link to comment
Share on other sites

@calbzam changing xlink metadata (adding expansion rules, changing target cs) doesn't force an empty changeset to be created on the target repo.  Thereby, it should not be unreasonable for us to expect that merging metadata changes will also not force an empty changeset to be created.  As I point out in the linked uservoice post, these empty changesets can lead to situations that the Plastic client was simply not meant to handle, leading users to an endless-loop scenario in the GUI.  You have described the reason that Plastic is creating empty changesets in one of Mikael's scenarios - whether or not this is a correct description of the current behavior, it is a poor way for the software to behave and it should be changed if you intend to describe Plastic as intuitive.

 

@Mikael Kalms I have just run into this very thing that you described:

On 6/5/2020 at 4:22 AM, Mikael Kalms said:

When someone changes something within a wxlinked repo on one task branch, and then merges that up to /main, then, under certain circumstances, this results -- a couple of steps further away -- in a merge operation from /main to another task branch resulting in a wxlink update _and_ an empty task branch in the wxlinked repo. This keeps perpetuating itself as long as there are overlapping task branches.

I made changes to the contents of an XLink from a task branch.  Before doing so, I modified the expansion rules so that the task branch and the mainline both expand to the same branch of the XLink's target repo, in an active effort to avoid creating any branch on the XLink's target repo.  This worked, but upon merging my task branch to the main one, despite the fact that the CS of the "theirs" XLink was a direct ancestor on the same branch of the "mine" XLink, I was required to merge them, creating an empty changeset.  Ever since, new task-branches appear to automatically create empty commits on new branches on the XLink's target repo.

 

I'll try to put together a video of the various issues that I'm having with XLink merges and empty changesets, as I expect the Plastic staff will not be convinced otherwise that we have any idea what we're talking about.

Link to comment
Share on other sites

On 6/8/2020 at 10:20 AM, calbzam said:

Hi Mikael,

1. The last changeset of the "/main" branch includes a change on the Xlink target. It's not a change on any file belonging to the Xlink but an edition on the XLink target changeset.

2. When you run the merge from "/main" to "/main/A2_2_taskk03", only the file conflicts appear in the merge panel and there are not any file revisions belonging to the Xlink in the merge. So you may expect that no merge operation will be necessary on the XLinked repo.

3. The reason why the merge operation happens on the Xlinked repo is because the edition on the Xlink target is actually a change that needs to be merged. The fact that the merge result changeset is empty confirms that there was not any file revision merged in this operation but because the only change to be merged is the edition on the Xlink target.

4. In summary: When you initially merged "/main/A2_1_task001" to "/main", you are not merging any change in the "/B2/foo2.txt" (becasue this change already exist on main from a previous merge), but also notice that you are actually merging the edition on the Xlink target. And this change in the Xlink target is also merged later from "/main" to "/main/A2_2_taskk03".


?name=inline1976076701.png



Regards,
Carlos.

Thanks for the explanation Carlos. I understand the reasoning. I have a problem with how plastic handles the wxlink merge (item nr 3 & 4).

 

If the B2 link had been a read-only xlink, then people would have done the work manually within the B2 workspace. The B2-related changes within the A2 workspace would only be changes to xlink's csetid. This would result in an xlink change first committed in cs:4@A2; this would get merged back to /main in cs:5@A2, and that same change would propagate to /main/A2_1_task001 in cs:6@A2. Since no extra branches/csets are being created in to B2, there would be no change to the xlink in cs:8@A2.

 

This changes when we use a wxlink for the B2 link. As soon as _anyone_ changes the csetid which B2 points to and there is at least one more active branch in parallel, then there will be at least one extra set of branches (and corresponding null commits) created when people begin to merge their branches. If people manage to always have overlapping branches, the extra branches and null commits will continue to occur on B2 until the end of time.

 

This is my desired behaviour: During a merge, where either the source, or the target, but not both, contain an update to the wxlinked csetid, I want:

- No new branch created in the wxlinked repo

- No empty cset created in the wxlinked repo

- The wxlinked csetid should be updated in the parent repo, just as if it had been a read-only xlink.

I want this behaviour during branch merges. I want this behaviour during cset cherry-picks.

 

I think I am missing something here. Will get back to this tomorrow, need to think more about it.

Link to comment
Share on other sites

Ok. So, my desired behaviour, summarized even shorter.

 

During a merge, when there is a wxlink change involved:

 - if the corresponding read-only xlink change would have resulted in an automatic merge, then I would expect the wxlink to be handled the same way: the wxlink is updated, but no changes are made within the wxlinked repo.

- If the corresponding read-only xlink change would have resulted in a merge conflict that required manual resolution, then I would expect the wxlink to be handled by automatic branch creation + a merge performed within the wxlinked repo.

 

The above logic fulfils two key criteria:

1) Merges will no longer produce branches with empty changesets in the wxlinked repo

2) Any merges that were handled by the current Plastic SCM logic, will continue to be handled by the proposed logic.

 

 

(For the time being, we will convert all our shared plug-in repos to be referenced via read-only xlinks. The wxlinks were nice but the extra "noise" in the wxlinked repos isn't worth it.)

Link to comment
Share on other sites

On 6/5/2020 at 12:34 PM, Mikael Kalms said:

@M-Pixel I have tried following the repro steps that you posted in the Uservoice to see whether it really is the same problem as I have been seeing. However, from what I can tell, the "good" and the "bad" case in the uservoice are identical procedures. There's a numbering mistake in the "bad" case and the wording for the xlink creation step is different -- but, again, I can't tell any functional difference between "good" and "bad". Can you please clarify this?

I tried following your repro steps. Using merge-to rather than merge-from does not result in any extra changesets for me. This is what my A repo looks like at the end:

image.png.5d74abfee0e9dd968b7d69cf8baefcd9.png

and this is what my B repo looks like at the end:

image.png.e2f31b6cffda44230601b20d9c6d158d.png

However -- I suspect that we are both seeing problems caused by the same root behaviour (any merge that involves a wxlink change results in a commit via the wxlink). We are both surprised because we think "hey, this case could be solved without touching the child repo -- after all, that's how it is handled with read-only xlinks, and without requiring manual conflict resolution". Right?

Link to comment
Share on other sites

I've been sharing tour feedback with the team. Let me share our thoughts abut this topic:
Regarding the writable XLinks to behave the same as readonly XLinks, it has some drawbacks.

- You cannot leave loaded the changeset from any branch because then, when Plastic needs to expand the branch in the Xlink to create the change, this branch may be created from a previous changeset. And at the end of the day,  the branch structure will be very chaotic and totally different from the parent repo strucuture. It would make more difficult to understand the history of the XLinked repo as it would be very different from the parent repo.
Readonly XLinks don't need to perform merges (they don't need to keep the merge trazability), but this is necessary for the writable Xlinks.

- Regarding to avoid the empty changesets in the Xlinked repo: 
In the specific scenario where the Xlink still doesn't have the branch created and you make a rebase (source in the same branch as the Xlink target), we could directly update the Xlink target instead of creating a branch with the changes from the old base . This way, you may be faking a bit the history, but you avoid the merge of the main branch to 
create an empty changeset that then will be propagated to other branchges.

eg:
1. We have a task branch with some changesets in the parent repo involving some changes in the XLinked repo. Xlink target changeset is cs:5
2. I make a merge from main to my task branch branch (rebase). In the main branch, the Xlink target was cs:10
3. A task branch is created in the Xlinked repo from cs:5 and a merge is performed of all the changes between cs:5-10.

The branch structure and behavior is the same as if you do the operation in the parent repo (a rebase to an empty branch).

 

New proposal based on your feedback:


1. We have a task branch with some changesets in the parent repo involving some changes in the XLinked repo. Xlink target changeset is cs:5
2. I make a merge from main to my task branch branch(rebase). In the main branch, the Xlink target was cs:10.
3. The Xlink target is updated to point to cs:10 of the Xlinked repo in main. This way, the Xlinked repo won't have the real history about what you did in the parent repo (because now the merge is not performed in the Xlinked repo) but according to your feedback, you prefer to lost this history in the XLinked repo if, this way, you can also avoid propagating empty changesets.

 

Regards,

Carlos.

Link to comment
Share on other sites

Yes. Your proposal would give the behaviour that I desire: it mimics the result that I would get, if I used only read-only xlinks, made changes to the parent and Xlinked repo separately, and manually updated the Xlink target when necessary.

(I haven't thought much about the traceability and the question "does the wxlinked repo structure make sense when viewed in relation to the parent repo structure?". I have only thought about whether the wxlinked repo structure makes sense on its own. I think the former results in empty changesets being good, and the latter results in empty changesets being bad.)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...