Difference between revisions of "Pinpoint regressions with Git"

 
(9 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Git}}
+
{{GitMenu}}
 
 
 
 
 
 
 
 
 
= How to bisect with Git =
 
= How to bisect with Git =
  
 
== How to find which commit introduced a regression ==
 
== How to find which commit introduced a regression ==
  
So you found a regression?  I.e. you know that the version worked perfectly that you had yesterday of, say, the [[Fiji Launcher]], but today it crashes?
+
So you found a regression?  I.e. you know that the version worked perfectly that you had yesterday of, say, the [[ImageJ Ops]] library, but today it crashes?
  
 
Git-bisect to the rescue!
 
Git-bisect to the rescue!
  
<pre>
+
<source lang="bash">
~/fiji$ git bisect start
+
git bisect start
~/fiji$ git bisect bad HEAD
+
git bisect bad HEAD
~/fiji$ git bisect good HEAD@{yesterday}
+
git bisect good HEAD@{yesterday}
</pre>
+
</source>
  
 
This will start the bisection process, i.e. it will try to find a revision that is as much "in the middle" between the bad commit(s) and the good commit(s) (you will mark more and more commits as good or bad in the process, and by inference, the ancestors of good commits will be considered good, and the offspring of bad commits will be considered bad, too), and let you test that.
 
This will start the bisection process, i.e. it will try to find a revision that is as much "in the middle" between the bad commit(s) and the good commit(s) (you will mark more and more commits as good or bad in the process, and by inference, the ancestors of good commits will be considered good, and the offspring of bad commits will be considered bad, too), and let you test that.
  
In our case, let's just test the Fiji launcher:
+
In our case, let's just run the unit tests:
  
<pre>
+
<source lang="bash">
~/fiji$ ./Build.sh fiji && ./fiji
+
mvn clean test
</pre>
+
</source>
  
If the test is undecided (for example, it does not compile at all), mark it with
+
If the test is undecided (e.g.: it does not compile, so you do not know if the unit test in question passes), mark it with
  
<pre>
+
<source lang="bash">
~/fiji$ git bisect skip
+
git bisect skip
</pre>
+
</source>
  
 
otherwise, mark it as "bad" or "good".
 
otherwise, mark it as "bad" or "good".
Line 36: Line 32:
 
Sooner or later (usually rather sooner), Git will tell you which commit is the culprit.  You can look at the corresponding patch with
 
Sooner or later (usually rather sooner), Git will tell you which commit is the culprit.  You can look at the corresponding patch with
  
<pre>
+
<source lang="bash">
~/fiji$ git show <commit name>
+
git show <commit name>
</pre>
+
</source>
  
 
where the commit name is that 40-digit hex string Git told you was the first bad commit.  Usually you end the bisection process then and there:
 
where the commit name is that 40-digit hex string Git told you was the first bad commit.  Usually you end the bisection process then and there:
  
<pre>
+
<source lang="bash">
~/fiji$ git bisect reset
+
git bisect reset
</pre>
+
</source>
  
 
This will bring you back to the revision and branch you were on before starting the bisection.
 
This will bring you back to the revision and branch you were on before starting the bisection.
Line 52: Line 48:
 
If there is an obvious flaw in the patch, just try to patch it.  You have to move to the first bad revision first:
 
If there is an obvious flaw in the patch, just try to patch it.  You have to move to the first bad revision first:
  
<pre>
+
<source lang="bash">
~/fiji$ git checkout <commit name>
+
git checkout <commit name>
</pre>
+
</source>
  
 
(This will warn you that you are not on any branch, but that is okay.)  Then just apply the fix you have in mind, and commit (after making sure that it worked, of course ;-).  Now, tag it with a temporary label:
 
(This will warn you that you are not on any branch, but that is okay.)  Then just apply the fix you have in mind, and commit (after making sure that it worked, of course ;-).  Now, tag it with a temporary label:
  
<pre>
+
<source lang="bash">
~/fiji$ git tag my-fix
+
git tag my-fix
</pre>
+
</source>
  
 
and go back to the branch you came from:
 
and go back to the branch you came from:
  
<pre>
+
<source lang="bash">
~/fiji$ git checkout master
+
git checkout master
</pre>
+
</source>
  
 
If you are unsure which branch you came from, look at the [[Git_reflogs|reflog]] first.
 
If you are unsure which branch you came from, look at the [[Git_reflogs|reflog]] first.
Line 72: Line 68:
 
Now you can cherry-pick (or forward-port) your patch:
 
Now you can cherry-pick (or forward-port) your patch:
  
<pre>
+
<source lang="bash">
~/fiji$ git cherry-pick my-fix
+
git cherry-pick my-fix
</pre>
+
</source>
  
 
If there are conflicts, resolve them and commit ("git commit fiji.cxx").
 
If there are conflicts, resolve them and commit ("git commit fiji.cxx").
Line 80: Line 76:
 
After that, you can get rid of the now-obsolete tag:
 
After that, you can get rid of the now-obsolete tag:
  
<pre>
+
<source lang="bash">
~/fiji$ git tag -d my-fix
+
git tag -d my-fix
</pre>
+
</source>
 +
 
 +
Note: instead of using a temporary tag, you can use the [[Git_reflogs|reflog]] of the HEAD ref (<code>git cherry-pick HEAD@{1}</code>), but if you are not familiar with the concept, tags are probably easier to handle.
 +
 
 +
= See also =
  
Note: instead of using a temporary tag, you can use the [[Git_reflogs|reflog]] of the HEAD ref ("git cherry-pick HEAD@{1}"), but if you are not familiar with the concept, tags are probably easier to handle.
+
* [http://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git#Binary-Search Binary search tutorial] in the Git book
  
 
[[Category:Git]]
 
[[Category:Git]]

Latest revision as of 10:43, 22 March 2017

Git Tutorials
Git for dummies
Git in Eclipse (EGit)
Git mini howto
Git workshop
Git Conflicts
Git topic branches
Git Notes
Git reflogs
Git submodule tutorial
Pinpoint regressions with Git
How to publish a Git repository
How to extract a subproject


How to bisect with Git

How to find which commit introduced a regression

So you found a regression? I.e. you know that the version worked perfectly that you had yesterday of, say, the ImageJ Ops library, but today it crashes?

Git-bisect to the rescue!

git bisect start
git bisect bad HEAD
git bisect good HEAD@{yesterday}

This will start the bisection process, i.e. it will try to find a revision that is as much "in the middle" between the bad commit(s) and the good commit(s) (you will mark more and more commits as good or bad in the process, and by inference, the ancestors of good commits will be considered good, and the offspring of bad commits will be considered bad, too), and let you test that.

In our case, let's just run the unit tests:

mvn clean test

If the test is undecided (e.g.: it does not compile, so you do not know if the unit test in question passes), mark it with

git bisect skip

otherwise, mark it as "bad" or "good".

Sooner or later (usually rather sooner), Git will tell you which commit is the culprit. You can look at the corresponding patch with

git show <commit name>

where the commit name is that 40-digit hex string Git told you was the first bad commit. Usually you end the bisection process then and there:

git bisect reset

This will bring you back to the revision and branch you were on before starting the bisection.

How to forward port a fix

If there is an obvious flaw in the patch, just try to patch it. You have to move to the first bad revision first:

git checkout <commit name>

(This will warn you that you are not on any branch, but that is okay.) Then just apply the fix you have in mind, and commit (after making sure that it worked, of course ;-). Now, tag it with a temporary label:

git tag my-fix

and go back to the branch you came from:

git checkout master

If you are unsure which branch you came from, look at the reflog first.

Now you can cherry-pick (or forward-port) your patch:

git cherry-pick my-fix

If there are conflicts, resolve them and commit ("git commit fiji.cxx").

After that, you can get rid of the now-obsolete tag:

git tag -d my-fix

Note: instead of using a temporary tag, you can use the reflog of the HEAD ref (git cherry-pick HEAD@{1}), but if you are not familiar with the concept, tags are probably easier to handle.

See also