Partons d'un rapport de bug sur le projet watchdog. Il est reporté que depuis la dernière version publique (0.9.0, datant de 2018), à un certain moment, une classe a perdu la possibilité d'être sérialisée à l'aide du module pickle. Comme cela fait une paire de commits à inspecter, git bisect est là pour nous.

Que fait la commande bisect ?
À partir des commits de départ et de fin, une vérification sera faite sur chaque commit intermédiaire. Pas tous les commits, car bisect utilise une recherche par dichotomie.
Et concernant la vérification, il peut s'agir d'une commande, d'un script voire d'une programme complet à exécuter ; et suivant le code de retour, bisect s'arrêtera ou continuera.


Voici le script qui sera utilisé pour trouver le commit foireux :

# File: check.py
import pickle
from watchdog.utils.dirsnapshot import DirectorySnapshot

pickle.dumps(DirectorySnapshot("./empty"))

Le dossier "empty" aura été crée auparavant.

Si j'exécute le script maintenant, à partir de la branche master (commit actuel 7a55f31) :

$ python check.py
Traceback (most recent call last):
  File "check.py", line 5, in <module>
    pickle.dumps(DirectorySnapshot("./empty"))
_pickle.PicklingError: Can't pickle <function DirectorySnapshot.<lambda> at 0x7f7fbd202c10>: attribute lookup DirectorySnapshot.<lambda> on watchdog.utils.dirsnapshot failed

Si j'exécute le script à partir du commit de la version 0.9.0, cela fonctionne :

$ git checkout v0.9.0
$ python check.py
$ echo $?
0

Donc on a bien le problème reproductible facilement.


Configurons maintenant bisect :

# git bisect start <mauvais commit> <bon commit>
$ git bisect start master v0.9.0
Bissection : 37 révisions à tester après ceci (à peu près 5 étapes)
[b8cf1b0afd88d17652271e6afb537d394c92a097] Generate sub created events only if recursive=True

Et c'est parti !

$ git bisect run python check.py
lancement de python check.py

Bissection : 18 révisions à tester après ceci (à peu près 4 étapes)
[af370b49ec319a0d64711fce46a7a1256e1e232f] Added missed st_size in win32stat for fixing broken tests against Python 2.7 on Windows (#558)
lancement de python check.py

Bissection : 9 révisions à tester après ceci (à peu près 3 étapes)
[18bb843ae9fa777a8f214c291a0e201f858bd9a1] Fix wrong source path after renaming a top level folder
lancement de python check.py
Traceback (most recent call last):
  File "check.py", line 5, in <module>
    pickle.dumps(DirectorySnapshot("./empty"))
_pickle.PicklingError: Can't pickle <function DirectorySnapshot.<lambda> at 0x7f20591acc10>: attribute lookup DirectorySnapshot.<lambda> on watchdog.utils.dirsnapshot failed

Bissection : 4 révisions à tester après ceci (à peu près 2 étapes)
[4fcf0377e4162dd5c1af8d6d2d0289e919562d0e] Added usage instruction to use with CIFS
lancement de python check.py

Bissection : 2 révisions à tester après ceci (à peu près 1 étape)
[a8db6350681966187d37588f6475295f5ff327d0] Add flake8 checks in tox and Python 3.8 in supported versions
lancement de python check.py

Bissection : 0 révision à tester après ceci (à peu près 1 étape)
[ecaa92756fe78d4771d23550c0935b0190769035] Snapshot: don't walk directories without read permissions (#573)
lancement de python check.py
Traceback (most recent call last):
  File "check.py", line 5, in <module>
    pickle.dumps(DirectorySnapshot("./empty"))
_pickle.PicklingError: Can't pickle <function DirectorySnapshot.<lambda> at 0x7feffc722b80>: attribute lookup DirectorySnapshot.<lambda> on watchdog.utils.dirsnapshot failed

Bissection : 0 révision à tester après ceci (à peu près 0 étape)
[c73eaadbb387f681879737ab2c45fcf56ac9a175] Fix issue with observed directory deleted (fixes #570)
lancement de python check.py
ecaa92756fe78d4771d23550c0935b0190769035 is the first bad commit
commit ecaa92756fe78d4771d23550c0935b0190769035
Author: Mickaël Schoentgen <contact@tiger-222.fr>
Date:   Fri Jun 14 14:24:32 2019 +0200

    Snapshot: don't walk directories without read permissions (#573)
    
    Original patch by Joshua Skelton (@joshuaskelly) on issue #408.
    
    * Add test + code refactoring
    
        - Rework DirectorySnapshot to allow monkeypatching .walk();
        - Added repr(DirectorySnapshotDiff) to ease catchng changes.

:040000 040000 9cf35e1fc81c6c7e49cb44119f5096141c30c727 362c460788443b70146f08d5f5657d087b1c45fa M      src
:040000 040000 7e332c4b9afde6bc6672546bd8156a7b7c519442 2c91460e5c964f78f321234b53952b2fcdab63aa M      tests
succès de la bissection

Ah ! Voici donc le commit foireux : Snapshot: don't walk directories without read permissions (#573).

Nous pouvons arrêter bisect :

git bisect reset

Il ne reste plus qu'à écrire le test de non régression, le fix et envoyer le patch.