git bisect run
automatyczna dwusieczna
Jeśli masz zautomatyzowany ./test
skrypt, który ma status wyjścia 0, jeśli test jest OK, możesz automatycznie znaleźć błąd za pomocą bisect run
:
git checkout KNOWN_BAD_COMMIT
git bisect start
# Confirm that our test script is correct, and fails on the bad commit.
./test
# Should output != 0.
echo $?
# Tell Git that the current commit is bad.
git bisect bad
# Same for a known good commit in the past.
git checkout KNOWN_GOOD_COMMIT
./test
# Should output 0.
echo $?
# After this, git automatically checks out to the commit
# in the middle of KNOWN_BAD_COMMIT and KNOWN_GOOD_COMMIT.
git bisect good
# Bisect automatically all the way to the first bad or last good rev.
git bisect run ./test
# End the bisect operation and checkout to master again.
git bisect reset
To oczywiście zakłada, że jeśli skrypt testowy ./test
jest śledzony przez git, to nie znika po wcześniejszym zatwierdzeniu podczas bisekcji.
Przekonałem się, że bardzo często możesz uciec, po prostu kopiując skrypt z drzewa z drzewa i prawdopodobnie bawiąc się PATH
zmiennymi podobnymi do niego i uruchamiając go stamtąd.
Oczywiście, jeśli infrastruktura testowa, od której test
zależy test, psuje się na starszych zatwierdzeniach, nie ma rozwiązania i trzeba będzie wykonać czynności ręcznie, decydując, jak testować zatwierdzenia jeden po drugim.
Przekonałem się jednak, że korzystanie z tej automatyzacji często działa i może być ogromną oszczędnością czasu dla wolniejszych testów leżących w zaległych zadaniach, gdzie możesz po prostu pozwolić jej działać przez noc i być może wykryć swój błąd do następnego ranka, warto próba.
Więcej porad
Pozostań przy pierwszym nieudanym zatwierdzeniu po bisecta zamiast wracać do master
:
git bisect reset HEAD
start
+ inicjał bad
i good
za jednym razem:
git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~
jest taki sam jak:
git checkout KNOWN_BAD_COMMIT
git bisect start
git bisect bad
git bisect good KNOWN_GOOD_COMMIT
Zobacz, co zostało przetestowane do tej pory (ręcznie good
i bad
lub run
):
git bisect log
Przykładowe dane wyjściowe:
git bisect log
git bisect start
# bad: [00b9fcdbe7e7d2579f212b51342f4d605e53253d] 9
git bisect bad 00b9fcdbe7e7d2579f212b51342f4d605e53253d
# good: [db7ec3d602db2d994fe981c0da55b7b85ca62566] 0
git bisect good db7ec3d602db2d994fe981c0da55b7b85ca62566
# good: [2461cd8ce8d3d1367ddb036c8f715c7b896397a5] 4
git bisect good 2461cd8ce8d3d1367ddb036c8f715c7b896397a5
# good: [8fbab5a3b44fd469a2da3830dac5c4c1358a87a0] 6
git bisect good 8fbab5a3b44fd469a2da3830dac5c4c1358a87a0
# bad: [dd2c05e71c246f9bcbd2fbe81deabf826c54be23] 8
git bisect bad dd2c05e71c246f9bcbd2fbe81deabf826c54be23
# bad: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05] 7
git bisect bad c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05
# first bad commit: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c0
Pokaż dobre i złe referencje w dzienniku git, aby uzyskać lepszy obraz czasu:
git log --decorate --pretty=fuller --simplify-by-decoration master
To pokazuje tylko zatwierdzenia z odpowiednim ref, co zmniejsza szarość, ale obejmuje automatycznie generowane ref:
refs/bisect/good*
refs/bisect/bad*
które mówią nam, które zobowiązania oznaczyliśmy jako dobre lub złe.
Rozważ to testowe repozytorium, jeśli chcesz pobawić się poleceniem.
Awaria jest szybka, sukces powolna
Czasami:
- awaria zdarza się szybko, np. jeden z pierwszych testów się psuje
- sukces zajmuje trochę czasu, np. zepsuty test zdaje, a wszystkie inne testy, których nie obchodzi nas przestrzeganie
W takich przypadkach, np. Zakładając, że awaria zawsze zdarza się w ciągu 5 sekund, a jeśli jesteśmy leniwi, aby uczynić test bardziej szczegółowym, tak jak powinniśmy, możemy użyć timeout
jak w:
#!/usr/bin/env bash
timeout 5 test-command
if [ $? -eq 1 ]; then
exit 1
fi
Działa to od timeout
wyjścia, 124
podczas gdy awaria test-command
wyjść 1
.
Magiczne statusy wyjścia
git bisect run
jest nieco wybredny co do statusów wyjścia:
cokolwiek powyżej 127 powoduje, że bisekcja zawodzi z czymś takim jak:
git bisect run failed:
exit code 134 from '../test -aa' is < 0 or >= 128
W szczególności C assert(0)
prowadzi do a SIGABRT
i wychodzi ze statusem 134, co jest bardzo denerwujące.
125 to magia i sprawia, że bieg jest pomijany git bisect skip
.
Ma to na celu pomóc w pomijaniu uszkodzonych wersji z niepowiązanych powodów.
Zobacz man git-bisect
szczegóły.
Więc możesz chcieć użyć czegoś takiego:
#!/usr/bin/env bash
set -eu
./build
status=0
./actual-test-command || status=$?
if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
status=1
fi
exit "$status"
Testowane na git 2.16.1.