Even with the best agile development practices, bugs sometimes slip in. You don't want to manually wade through hundreds of commits and thousands or tens of thousands of lines of code to find your bug. See how find your bug fast using Git, the best (and free) version control software tool. If you are still using CVS, Subversion, or costly commercial version control, you are missing out.
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Automate Debugging with git bisect
1. cbell@CamilleBellConsul/ng.com
1
Automated Debugging with
git bisect
TDD
Camille
Bell
Agile
Coach
/
Rails
Developer
cbell@CamilleBellConsul9ng.com
Twi6er
@agilecamille
h;p://www.slideshare.net/Camille_Bell/
2. cbell@CamilleBellConsul/ng.com
2
How
do
you
find
a
bug
in
a
large
code
base
with
lots
of
commits?
1st
2nd
3rd
4th
97th
98th
99th
100th
3. cbell@CamilleBellConsul/ng.com
3
Debugging
Op9ons
• Manually
inspect
all
the
code
and
hope
you
find
the
bug
!"
• Logically
eliminate
some
of
the
code,
inspect
all
the
rest
and
hope
you
find
the
bug
!
• Use
automa9on
to
find
your
bug
fast
☺
4. cbell@CamilleBellConsul/ng.com
4
Steps
to
Target
the
Buggy
Code
• Create
new
or
use
an
exis9ng
automated
bug
detector
to
dis9nguish
between
bug
free
code
from
buggy
code
(usually
an
automated
test)
• Determine
the
bug
commit
range
– Use
git log
if
needed
• Use
git bisect
– Run
the
test
– Use
git diff
to
narrow
bug
to
code
lines
5. cbell@CamilleBellConsul/ng.com
5
Automa9ng
Bug
Detec9on
• Perhaps
you
already
have
a
good
automated
test,
but
weren’t
running
it
with
every
commit.
Use
that
test
(and
set
up
a
CI
server
soon).
• If
not
create
a
new
test
that
should
fail
(RED)
when
the
bug
is
present
and
pass
(GREEN)
when
the
bug
is
fixed.
– Write
the
test
in
whatever
test
language
makes
sense
(e.g.
RSpec
for
low
level
Ruby,
Cucumber
high
level
behavior,
Jasmine
for
JavaScript,
JUnit
for
Java,
NUnit
for
C#,
etc.)
6. cbell@CamilleBellConsul/ng.com
6
Verify
the
Test
Catches
the
Bug
• Run
the
test
on
the
latest
buggy
code
and
watch
it
fail
(RED).
• Go
back
to
a
known
good
commit,
run
the
test
and
watch
it
pass
(GREEN).
7. cbell@CamilleBellConsul/ng.com
7
$ rspec . –color
F.
Failures:
1) Account depositing to account produces the correct balance
when 9 dollars is deposited the balance is 10 dollars
Failure/Error: @account.balance.should == 1000
expected: 1000
got: 999.9999 (using ==)
# ./account_spec.rb:15:in `block (3 levels) in <top
(required)>'
Finished in 0.00058 seconds
2 examples, 1 failure
Failed examples:
rspec ./account_spec.rb:12 # Account depositing to account
produces the correct balance when 9 dollars is deposited the
balance is 10 dollars
$
Verifying
Failure
on
Known
Bad
Commit
8. cbell@CamilleBellConsul/ng.com
8
$ rspec . –color
..
Finished in 0.00047 seconds
2 examples, 0 failures
$
Verifying
Success
on
a
Known
Good
Commit
9. cbell@CamilleBellConsul/ng.com
9
Running
git bisect
• Start
with
a
known
bad
git repository
– $
git bisect start
– $
git bisect bad
– $
git bisect good <good_commit>
• Run
your
tests
• If
the
test
passes
– $
git bisect good
• If
the
test
fails
– $ git bisect bad
• Repeat
un9l
you
find
the
bad
commit
Use
either
tag
or
git
commit
#
If
needed
checkout
a
bad
git
commit
#
10. cbell@CamilleBellConsul/ng.com
10
!"#"#"#"#" #"#"#"
Determine
the
Bug
Commit
Range:
•
The
last
known
commit
without
the
bug
•
The
first
commit
aeer
the
bug
observed
Star9ng
Good
Commit
Star9ng
Bad
Commit
Bug
Inserted
Within
These
8
Commits
11. cbell@CamilleBellConsul/ng.com
11
git bisect does
a
binary
search
through
your
commit
range.
!"#"#"#"#" #"#"#"
Good
Commit
Bad
Commit
bisect
Star9ng
Commit
bisect begins
with
the
commit
halfway
between
the
known
good
commit
and
the
known
bad
commit
12. cbell@CamilleBellConsul/ng.com
12
Assume
the
1st
test
on
bisect failed.
!"!"#"#"#" !"!"!"
Good
Commit
Bad
Commit
bisect
Next
Commit
Then
bisect would
select
the
commit
between
the
known
good
commit
and
the
last
bad
bisect
Bad
Commit
Can
ignore
these
Commits
Bug
inserted
Within
These
4
Commits
13. cbell@CamilleBellConsul/ng.com
13
Assume
the
2nd
test
on
bisect passed.
!"!"#" !"!"!"
Good
Commit
Bad
Commit
Then
bisect would
select
the
commit
between
the
last
known
good
commit
and
the
last
bad
bisect
Bad
Commit
Can
ignore
these
Commits
Bug
inserted
Within
These
2
Commits
Can
ignore
these
Commits
Good
Commit
bisect
Next
Commit
14. cbell@CamilleBellConsul/ng.com
14
If
the
3rd
test
on
bisect failed.
!"!"!" !"!"!"
Good
Commit
Bad
Commit
Then
that
commit
is
where
the
bug
was
inserted.
Bad
Commit
Can
ignore
these
Commits
Bug
inserted
Within
These
2
Commits
Can
ignore
these
Commits
Good
Commit
Final
Commit
Failed
Test
15. cbell@CamilleBellConsul/ng.com
15
If
the
3rd
test
on
bisect passed.
!"!"!"!"!"
Good
Commit
Bad
Commit
Then
the
next
commit
is
where
the
bug
was
inserted.
Bad
Commit
Can
ignore
these
Commits
Bug
inserted
Within
These
2
Commits
Can
ignore
these
Commits
Good
Commit
Final
Commit
Passed
Test
16. cbell@CamilleBellConsul/ng.com
16
Example
Test
require_rela9ve
'account'
describe
Account
do
before
do
@star9ng_balance_in_pennies
=
100
@account
=
Account.new(@star9ng_balance_in_pennies)
end
context
"deposi9ng
to
account
produces
the
correct
balance"
do
it
"when
9
dollars
is
deposited
the
balance
is
10
dollars"
do
deposit_amount_in_pennies
=
900
@account.deposit(deposit_amount_in_pennies)
@account.balance.should
==
1000
end
end
end
17. cbell@CamilleBellConsul/ng.com
17
Some9mes
the
Commit
Messages
from
git log Pinpoint
the
Bug
$ git log --pretty="%h - %s"
561bb3a - added withdrawal and deposit messages
6ca7ee1 - added error
c546d1f - added to_s
1974592 - added withdrawal
7a8c508 - Initial commit
But
usually
the
log
only
provides
a
range
Known
Good
Commit
Known
Bad
Commit
18. cbell@CamilleBellConsul/ng.com
18
Star9ng
up
git bisect with
Test
on
the
Middle
git Commit
$ git bisect start
Already on 'master’
$ git bisect bad
$ git bisect good 7a8c508
Bisecting: 1 revision left to test after this (roughly
1 step)
[c546d1f89b5b0c14ab160e227fc83d62fb780e6f] added to_s
$ rspec . --color
..
Finished in 0.00071 seconds
2 examples, 0 failures
$ git bisect good
Bisecting: 0 revisions left to test after this (roughly
0 steps)
[6ca7ee1909bf0b3f7344feee25a5b44a97602e2c] added error
Known
Good
Commit
Known
Bad
Commit
If
the
tests
pass,
Tell
git bisect good
Otherwise
git bisect bad
C
O
M
M
I
T
19. cbell@CamilleBellConsul/ng.com
19
Test
on
the
final
git commit
$ rspec . --color
F.
Failures:
1) Account depositing to account produces the correct balance when 9
dollars is deposited the balance is 10 dollars
Failure/Error: @account.balance.should == 1000
expected: 1000
got: 999.9999 (using ==)
# ./account_spec.rb:15:in `block (3 levels) in <top (required)>'
Finished in 0.00053 seconds
2 examples, 1 failure
Failed examples:
rspec ./account_spec.rb:12 # Account depositing to account produces
the correct balance when 9 dollars is deposited the balance is 10
dollars
$
20. cbell@CamilleBellConsul/ng.com
20
$ git diff c546d1f 6ca7ee1
diff --git a/account.rb b/account.rb
index a979e55..0a572ef 100644
--- a/account.rb
+++ b/account.rb
@@ -5,7 +5,7 @@ class Account
end
def deposit(new_deposit)
- @balance += new_deposit
+ @balance += (new_deposit - 0.0001)
end
def withdrawl(new_withdrawl)
$
git diff Targets
the
Bug
Even
More
Good
Commit
Just
Before
Bug
Commit
Where
Bug
First
Appeared
Bug
inserted
in
one
or
more
of
the
+
lines.
21. cbell@CamilleBellConsul/ng.com
21
Thank You for Listening
Camille
Bell
Agile
Coach
/
Rails
Developer
cbell@CamilleBellConsul9ng.com
Twi6er
@agilecamille
h;p://www.slideshare.net/Camille_Bell/