Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ugultopu/3c1f7a0d82a7fde98b70950126c1408e to your computer and use it in GitHub Desktop.
Save ugultopu/3c1f7a0d82a7fde98b70950126c1408e to your computer and use it in GitHub Desktop.
Or, how to use `git bisect`?

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 git@github.com: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:

{
  // Other fields...
  "dependencies": {
    // Other dependencies...
    // The following points to the built files of our local copy of TypeORM. Note that the file path
    // can either be relative, or absolute.
    "typeorm": "file:../typeorm/build/package",
    // Other dependencies...
  }
  // Other fields...
}

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 <dmzt08@gmail.com>
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.

Source

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment