Every Bubble app has at least two versions, live (the version exposed to the world) and at least one development version, to which you make changes. All apps by default come with a single development version, called "test," although users on Team, Professional, and Dedicated plans can create more.
Within a version, bubble lets you revert changes to your application in case something went wrong. Save points make it easy to revert to particular point, but since changes are stored continuously, you can revert to any specified time. How far back in time you can revert is determined by your plan.
As explained above, your application has at least two versions, live and test. Live represents the publicly-accessible version of the app, test is the version you make changes to. When you are ready, you can deploy your changes from test to live. Users on Team, Production, and Dedicated plans can have multiple development versions.
Functionality related to version control can be found in the version control dropdown, found just to the left of the preview button:
The name of the currently active branch is displayed in the toolbar, as well as at the top of the menu. Other versions can be selected from the menu below, or a new one can be created by clicking "Create a new version." The top portion of the menu allows you to perform operations relating to the current version: deploy it to live, create a save point, revert it to a previous time or save point (click "History"), or sync recent changes to live with it.
Clicking the "History" button gets you a popup that allows you to revert the current version to a previous point in time, as limited by your plan. Changes to Bubble apps are saved in a granular fashion, in the manner of an infinite undo. It's therefore possible to revert your version to any point in time. You can also create save points (directly from the version dropdown), which make it easy to revert the app to a particular state. You can think of save points as annotations, labels on a particular time and date you can apply for convenience. Histories are specific to versions, which means that when you deploy to live, live's will show your deployment but not development version save points leading up to it.
Please note that times are in your local timezone, and that reverting does not affect the state of the database.
When a user of a multi-version app deploys their version to live, the other versions become out-of-sync with live and need to be synced. Syncing a version with live incorporates the newly deployed changes, making it possible to deploy. In the event that one of the deployed changes conflicts directly, the user will be shown both options and prompted to choose which change to keep. Once an app has been synced it can be deployed.
The development version is the one you work on, while the live version is read-only and the one your users interact with in production. You restore your application in development mode, and if you need to deploy an older version of your application to production, you then deploy (push) to live (see above for more details).
Summary: All development versions share a common "test" database, although data associated with custom types you've created remain associated with specific versions. This means that although records of "userA-type' will exist in the same database referenced by userB, they will not show up in userB's version until userB syncs.
Detailed explanation: As noted above, every app has a live version and at least one development version. Records in the live database are independent of records in the development database. You can copy the live database to replace the development database or vice versa, but, for example, a user signing up in your live version will not automatically also create a record in your development version.
But what happens with multiple development versions? A principle to keep in mind is that all your development versions share the same "test" database but data associated with custom types remain associated with specific versions. To explain this further, here are a few scenarios (assuming A and B are both development versions of an app):
A is your main development branch and has a certain set of custom data types with different fields, and a number of records in it. When you create a new version, B, based off of A, B will also have those same custom data types, fields and records
After creating B from A, if you add new records to B of an existing data type, those new records will show up to A as well
Let's assume that A has a custom data type "Employee" with a set of fields. B is created from A, so B also has the Employee data type. If you add the new field "Birthday" (type text) to Employee in A, it will not automatically show up in B.
If you then add a new field "Birthday" (type text) to Employee in B, it will not refer to the same "Birthday" field from A, meaning that for the same record, A and B have their own independent "Birthday" fields that store data independently
Let's assume that B has already been created from A. If you then add a new custom data type "Project" in A, it will not automatically show up in B
However (and this is the tricky part!), if you created a new custom data type "Project" in B as well, it will refer to the same Project as A!