Every database object shall be stored in a separate file in version control system. Version control system could contain files like in this example:
|- tables
|- employees.sql
|- contracts.sql
|- packages
|- contract_api.sql
|- functions
|- get_employee_name.sql
...etc...
Whenever you modify some DB object, then you must also modify the appropriate SQL (DDL) file in the version control system. For example, if you modify package *contract_api*, then you update file *contract_api.sql*. As this file has been modified - it can be installed, say, by a continuous integration engine.
BUT, as you know, there are DDL scripts, that can't be executed twice. For example 'CREATE TABLE mytable...' script can be executed only once. And if your system is already in production, then you can't afford 'DROP TABLE mytable' statement in the header of your 'CREATE TABLE...' script. Therefore for production systems you need to create so called delta scripts that will deliver only changes. In this case you could simply create a new file called employees_upd01.sql that contains statement 'ALTER TABLE mytable ADD COLUMN...'.
After some time your repository could look like this:
|- tables
|- employees.sql
|- employees_upgr20091001.sql
|- employees_upgr20091004.sql
|- contracts.sql
|- packages
|- contract_api.sql
|- functions
|- get_employee_name.sql
...etc...
And this is OK, because:
1) when you need to deliver todays' incremental changes to database - you deploy files that were modified today
2) if you need to deploy a clean installation of your system - you run all scripts in order, e.g. first employees.sql, then *employees_upgr20091001.sql*, etc.
As each DB object is in a separate file in version control system, you have a good control over all changes.