Full Video Transcript
Hey there, I'm Jase Lindgren, a solutions engineer at Perforce Software, and today I'm going to be going quickly through the different types of streams in Helix Core. You've probably heard about using Streams before, but I find that a lot of people are confused about the different types of streams and what you would actually use them for. So in this, I want to go over what the different types of streams are, talk a little bit about how you might use them and show just some very quick examples of that.
The first three on this list are the most common, and you could think of them as normal streams. So that's the mainline stream, the development stream, and the release stream. And we'll see as we go through that these three are fairly similar to each other and just
are used for slightly different things. And then we have two extra ones. One is virtual stream and the other is a task stream. And these ones work differently from the other three and have some very cool, very powerful use cases, but they are a little bit different.
So first we're gonna go over the top three, and then those extra two. Now you can see on the left side that I have them all shown as they would show up in P4V. And that is that if I create these streams in P4V and I open up the stream graph, this is how these would look if I made these streams with these names. And you'll notice that each one has a different icon as well as some other visual differences like color or it's hard to tell in this image, but virtual has a dotted line instead of a solid line around it.
And you can also see that the arrows between them are different, and this helps you to understand the relationship between them. But the main thing that I want to show here in this is that the way the stream graph is laid out is going from the most stable at the top to the least stable toward the bottom. And that's where things like our motto of merge down copy up comes from.
The idea being that you would do any merges between these streams, you could think of that like a merge between branches that you're gonna do that merge on the lower stream, which is the less stable one. That's where you resolve any conflicts, make sure everything's working, and then when you go up, you're just doing a straight copy because you've already resolved any conflicts below that so that then you end up with only stable things ending up in the higher stream. So you can see here that a release stream is the most stable at the top. And that makes sense, because you want your releases to be stable.
So let's get into the details of each of these. The one to start with here is the mainline stream. So this one is the one type of stream that you have to have in a stream depot. If you make a Streams depot, in order to do anything in it, you need streams to work in.
And in order to create any of these other types of streams, we need to have a mainline that's going to be the parent of it. So you could think of this in terms of trunk based development if you want, but the idea is that this is the parent of all the other streams. It's generally considered stable. So it's not where you're gonna really be trying things implementing new features, but it could be because of the fact that we have these release streams that are even more stable above it.
We could still do some fooling around in here, but generally speaking, you want to keep your main line pretty consistently working, whether that's a game engine project or code or whatever it is. You want that one to be stable enough that it can work. And then underneath that we have the development stream.
So the development stream is basically the same idea but it's a child of that mainline, but it's for more frequent changes, more work in progress. It's generally considered more flexible. You can break stuff when you're in there, and this is where you'll be working most of the time.
One thing that I'm not showing on my graph here is that you can have multiple children. So a mainline stream could have multiple different development streams underneath it. So you could segment things out into different projects, different features, maybe separate ones for external vendors versus your internal teams, however you want to do that. And we can see here that this up and down arrow from the mainline stream above it goes both up and down.
So the idea being that we can merge down from the mainline and that we can copy up from development into the mainline. So these two work very similar to each other and data can flow back and forth between them. The only difference here being that merge down copy up thing that I mentioned, so generally we're going to merge down, meaning it's okay if we have conflict because we're gonna resolve those in development, but when we go to copy up, It's by default only going to let you do that, or at least we’ll strongly encourage you not to do that if there are any kind of conflict in that mainline stream.
The idea being that that needs to stay stable so you've resolved things below it. Now, on the other side, we have the release stream. The release stream is the most stable. It's generally considered locked in place in terms of this being a snapshot in time, and you can see by the arrow here that
changes can merge down. So they can come out of it and merge down into the main line or whatever stream is below it, but it's not set up to receive any new copies in. So a way to think about this is if we release version one of our software, at that point we have our mainline stream. Everything seems good.
We decide that this is ready to go out and be released, we would then create a release stream. What that would do is it would branch all of those files into that stream at that particular point in time, and then we can continue working on our mainline stream as we develop 1.1 or version two or whatever it is. But that release stream is a snapshot, essentially, of what the project looked like at that release.
But if we notice a bug or there's some sort of issue in that release, we can go into that release stream itself, fix those problems there and then merge that bug fix back down into Mainline so that future versions will have that same bug fix. But we're not going to copy things back up from mainline into that release because we've moved on and maybe done other things and it hasn't been tested. So then if we wanted to make a new release, like a 1.1,
we would then make a new release stream. That's the idea behind that. And release streams can have children off of them. So you could have a development stream off of a release stream or another release stream off of another release stream.
You can do all sorts of things, but this is the general simple workflow right here. So you can see how between mainline and development being most of where you work, and then release streams being this slightly different special way to do this snapshot in time. Now let’s get into the funky ones. So the first of those is the virtual stream.
So a virtual stream is not a real stream. And what I mean by that is each of the streams we’ve talked about so far creates a branch of those files. So you could think of that like this separate copy of that file or an alternate dimension version of that file. And so if I change a file in the development stream and someone else is working in the mainline stream, they won't see my changes at all until we do that merge down, copy up, and then that's bringing those changes in.
So it allows you to work in isolation in the separate branch. What a virtual stream does is not that. So you can see that the line between the development here and virtual stream is not an up arrow or a down arrow. It's just this straight line that connects these.
And what that means is that I'm actually working in my parent stream, which in this case is the stream called development, but I could have a virtual stream that's a child of a mainline, a child of a release, a child of a task stream, any of the others. But in this case, what's happening is I'm still working in development, but the virtual stream allows me to change my view. A filtered view of the parent’s stream. So what I mean by that is, say I have a huge project with 20 different components, all which have thousands of files in each of them, and I want to be able to work on just one of those.
And rather than working in the development stream, and when I sync my workspace, all the files from all those folders are going to sync to me. But I might not need all of that. I might only need one folder worth of stuff to work on. So what I can do is I can make a virtual stream.
Filter that view so it only sees one of those folders or maybe only certain files within certain folders, or only a few different folders. It's very flexible. And then I can open this virtual stream so that I don't have to load all of that. I can work more efficiently.
I can just see what I need. But any change I make is actually being made directly in the development branch of these files. So anyone else working in development or a different virtual stream off of development. In this example, if their virtual stream saw some files in common with mine, they would see my changes as soon as I submitted those.
So I find these to be incredibly useful, especially for just simplifying, rather than making all these separate branches of files. So it allows other people to get your changes sooner. You get their changes sooner, but you can limit what it is that you're seeing when you're working. And then lastly, we have task streams.
The idea behind these is that these are short-lived for a task. The idea is that you create a task stream, you would work on that task. And once you're done, you would then either delete or unload that task stream. A few things to know about this.
So here I have it coming off of a virtual stream, but I find more often this would come off of a development stream even off of your main line, but usually it will be a child of a development stream. You can do it however you want though. The idea with a task stream is that when you create it and you branch all the files from its parent. When other users look at the depot view, they will not see those branched files.
It's like they're, they've been branched in this lighter weight kind of invisible way until you make a change to one of those files and submit that to your task stream. Then it will actually create a real branched version of that that other people can see. For example, in the Depot panel in P4V, the idea here is that you can experiment and work on things and you're not creating a whole lot of extra copies of everything just because you're working on one little task. This is in contrast to a development stream
where we might be continually working on things. This is continually part of a much larger, longer term project, whereas the task stream is just, maybe I'm just making a tiny little change to the UI and I wanna do that separately so I'm not screwing people up while I'm working on it. But I'm not making a big, massive feature that's gonna affect a lot of things and I have a big team working on together. One thing to keep in mind with task streams though, is that the names for them have to be unique forever, even after they've been deleted.
You cannot make another task stream that has the same name. So as a general best practice, it's good to name them something like, you know, your username, what the task is, and then some kind of code. So if you have some kind of ticketing system for these tasks, or you have some kind of identifier for different jobs or tasks, things like that, put that in the task stream’s name so that then you're not likely to use that again. One thing with the deleting or unloading,essentially those both will appear the same to users. When you unload a stream, it's going to move it into this separate unloaded depot so it won't show up in the stream view. Other people won't see it, but you can get it back. So if there's a chance you might want to go back to this particular task stream to make some new changes to that particular thing, then unloading might be a better option.
But if you're sure that that's done, maybe it's already been copied up into a release and that's done, you could delete it and just not worry about going back to that. And if you do need to make changes, make a new one. So that was the overview of the five different types of streams. In a future video, I'd like to talk about the different ways that you can customize stream specs to do really powerful things like stream components, import paths, writeable imports, excludes, isolates, things like that.
But I hope that this at least gives you a rough sense of what you would use these for.