Let's say that on a previous version of a library, everything was working fine but after you have upgraded, a bug started to occur. Obviously, this change of behavior was introduced later to the library (via a commit). If we were able to detect which change has introduced this, we could:
- Fork our own version of the library.
- In our own fork, revert the change that introduced the changed behavior.
- Use our own fork of the library.
To discover which commit has introduced this change, we can use the "bisect" command in Git. "git bisect" is basically a binary search, where Git helps us. That is, it is nothing but a binary search (of commits), where the "bisect" command does the "boring" stuff like taking a note of which commit was a good commit, and which commit was a bad commit, etc. Let's discover "git bisect" with a concrete example:
We'll give an example over a Node.js project which depends on a library named TypeORM. That is, let's say that our Node.js project depends on this library named TypeORM. Our project depended on version 0.2.30 of TypeORM. At this version, everything worked perfectly. After I upgraded TypeORM to version 0.2.44 (which is the latest version as of writing this document), I started to the following error:
Error: Column "columnNameGoesHere" of Entity "EntityNameGoesHere" is defined as enum, but missing "enum" or "enumName" properties.
A bit of web search revealed that this error occurs when you use the same enum for multiple columns. This is not a good behavior, because we don't want to have essentially duplicate enums just to prevent this error. Hence, we want to discover which change has introduced this change, fork our own version of TypeORM and revert this change in our own fork.
As I've said above, this error did not occur on version 0.2.30, but occurred on version 0.2.44. This means that the commit whose tag value is 0.2.30 is the first "good" commit that we know of, and the commit whose tag value is 0.2.44 is the first "bad" commit that we know of. Let's keep this information in mind, we'll get back to it.
Now, we need to clone the TypeORM repository to our machine:
git clone [email protected]:typeorm/typeorm.git
cd typeorm
Reading the development instructions for the TypeORM project (the file named "DEVELOPER.md"), we understand that we can build the TypeORM project by running the script named "package". The same file also says that the built code would be located in "build/package".
Of course, before running the build script, we first need to install the dependencies. Hence, let's do that. That is, let's install the dependencies and build TypeORM:
npm install
npm run package
After these commands, we can observe that the built TypeORM library is located in build/package
under the directory that we checked out TypeORM.
Now, from our project, let's point TypeORM to our local copy, instead of the one in the npm repository. So, in our project's package.json
:
And that's it! Now, our project depends on our local copy of TypeORM. Now, we can start "git bisect" to discover which commit has introduced the bug.
To do so, we switch to the directory of TypeORM and we run:
git bisect start
This starts "git bisect". Now, we need to specify one good and one bad commit (ref). That is, one ref where the library behaves as expected, and one ref that it does not. We already know that these are versions 0.2.30 and 0.2.44 respectively, so let's do that:
git bisect bad 0.2.44
git bisect good 0.2.30
Now, "git bisect" has started. That is, "git bisect" will check out the commit that is right in the middle of these "good" and "bad" commits.
Now, we simply need to recompile TypeORM and test if our project will work with this version. Note that we might also need to re-install the dependencies before compiling, since there might be new dependencies. That is:
npm install
npm run package
Now, we switch to the directory of our project, and test if our project will work with this version. Note that before testing, we do not need to run npm install typeorm
from our project, since we are already pointing to the directory of the build output of our local copy of TypeORM. That is, all we need to do is to switch to our project's directory and run the command / script / etc. that will test if our project works with this version of TypeORM, without the need of running npm install typeorm
beforehand.
After testing, we switch back to the directory of our own local copy of TypeORM. If everything worked in our test in our project, from the directory of TypeORM, we run:
git bisect good
If, on the other hand, the bug occurred again, we run:
git bisect bad
After running either of these commands, "git bisect" will select another commit (by following the binary search approach) for us to test. We will repeat the same steps. That is, we will re-compile TypeORM by running:
npm install
npm run package
and then, we'll switch to our own project and test if our project works with this version of TypeORM. Again, we do not need to run npm install typeorm
before testing, since we already point to the build output of TypeORM from our own project (that is, "typeorm": "file:../typeorm/build/package"
). After testing, we switch back to the directory of our own local copy of TypeORM, and we specify if that version was good or bad, by running either git bisect good
or git bisect bad
. We repeat this until "git bisect" tells us which commit was the "first bad commit". That is, after repeating these steps enough, "git bisect" will give an output something like:
$ git bisect good
724d80bf1aacedfc139ad09fe5842cad8fdb2893 is the first bad commit
commit 724d80bf1aacedfc139ad09fe5842cad8fdb2893
Author: AlexMesser <[email protected]>
Date: Fri Mar 5 17:17:58 2021 +0500
fix: fixed all known enum issues (#7419)
* fix #5371
* fix #6471;
fix: `enumName` changes not handled;
fix: `enumName` does not handle table schema;
* fixed falling test;
* added test for #7217
* fix #6047, #7283;
* fix #5871
* added support for `enumName` in `joinColumns` (#5729)
* fix #5478
* fixed falling test;
updated `postgres-enum` test;
* added column `array` property change detection (#5882);
updated `postgres-enum` test;
* fix #5275
* added validation for `enum` property (#2233)
* fix #5648
* improved missing "enum" or "enumName" properties validation;
* fix #4897, #6376
* lint fix;
* fixed falling tests;
* fixed falling tests;
* removed .only
* fix #6115
src/driver/aurora-data-api/AuroraDataApiDriver.ts | 4 +
.../aurora-data-api/AuroraDataApiQueryRunner.ts | 2 +-
src/driver/mysql/MysqlDriver.ts | 21 ++--
src/driver/mysql/MysqlQueryRunner.ts | 4 +-
src/driver/postgres/PostgresDriver.ts | 48 ++++++---
src/driver/postgres/PostgresQueryRunner.ts | 120 ++++++++++++---------
src/driver/sqlite-abstract/AbstractSqliteDriver.ts | 2 +-
.../sqlite-abstract/AbstractSqliteQueryRunner.ts | 1 -
src/driver/sqlserver/SqlServerDriver.ts | 28 ++++-
src/driver/sqlserver/SqlServerQueryRunner.ts | 32 +++---
src/metadata-builder/EntityMetadataValidator.ts | 2 +
.../JunctionEntityMetadataBuilder.ts | 4 +
src/metadata-builder/RelationJoinColumnBuilder.ts | 4 +-
src/naming-strategy/DefaultNamingStrategy.ts | 7 +-
src/naming-strategy/NamingStrategyInterface.ts | 7 +-
.../column-types/mssql/column-types-mssql.ts | 4 +-
.../column-types/postgres-enum/entity/Post.ts | 5 +-
.../column-types/postgres-enum/postgres-enum.ts | 117 +++++++++++++++++++-
.../column-types/sqlite/column-types-sqlite.ts | 4 +-
.../database-schema/enums/entity/EnumEntity.ts | 8 ++
test/functional/database-schema/enums/enums.ts | 12 ++-
test/github-issues/4897/entity/SomeEntity.ts | 33 ++++++
test/github-issues/4897/issue-4897.ts | 30 ++++++
test/github-issues/5275/entity/UserEntity.ts | 23 ++++
test/github-issues/5275/issue-5275.ts | 59 ++++++++++
test/github-issues/5478/entity/UserEntity.ts | 16 +++
test/github-issues/5478/issue-5478.ts | 45 ++++++++
test/github-issues/5871/entity/SomeEntity.ts | 16 +++
test/github-issues/5871/issue-5871.ts | 30 ++++++
test/github-issues/6115/entity/v1/MetricEntity.ts | 29 +++++
test/github-issues/6115/entity/v2/MetricEntity.ts | 29 +++++
test/github-issues/6115/issue-6115.ts | 87 +++++++++++++++
test/github-issues/6471/entity/SomeEntity.ts | 35 ++++++
test/github-issues/6471/issue-6471.ts | 40 +++++++
test/github-issues/7217/entity/UserEntity.ts | 23 ++++
test/github-issues/7217/issue-7217.ts | 34 ++++++
test/github-issues/7283/entity/AccessEvent.ts | 15 +++
test/github-issues/7283/entity/Employee.ts | 16 +++
test/github-issues/7283/issue-7283.ts | 35 ++++++
39 files changed, 921 insertions(+), 110 deletions(-)
create mode 100644 test/github-issues/4897/entity/SomeEntity.ts
create mode 100644 test/github-issues/4897/issue-4897.ts
create mode 100644 test/github-issues/5275/entity/UserEntity.ts
create mode 100644 test/github-issues/5275/issue-5275.ts
create mode 100644 test/github-issues/5478/entity/UserEntity.ts
create mode 100644 test/github-issues/5478/issue-5478.ts
create mode 100644 test/github-issues/5871/entity/SomeEntity.ts
create mode 100644 test/github-issues/5871/issue-5871.ts
create mode 100644 test/github-issues/6115/entity/v1/MetricEntity.ts
create mode 100644 test/github-issues/6115/entity/v2/MetricEntity.ts
create mode 100644 test/github-issues/6115/issue-6115.ts
create mode 100644 test/github-issues/6471/entity/SomeEntity.ts
create mode 100644 test/github-issues/6471/issue-6471.ts
create mode 100644 test/github-issues/7217/entity/UserEntity.ts
create mode 100644 test/github-issues/7217/issue-7217.ts
create mode 100644 test/github-issues/7283/entity/AccessEvent.ts
create mode 100644 test/github-issues/7283/entity/Employee.ts
create mode 100644 test/github-issues/7283/issue-7283.ts
That is, "git bisect" tells us which commit was the first bad commit and immediately after, it puts an output of git show <bad commit>
for our convenience.
And that's it! From this point on, we need to examine that "first bad commit" manually and try to understand which change has introduced the change in the behavior (that is, understand which change has introduced "the bug"). After determining it, we can fork our own version of TypeORM, create a new commit that reverts that change and from our own project, depend on our own fork of TypeORM, instead of depending on the "original" copy.