Introduction

In his book Software Design X-Rays, Adam Tornhill shows a nice metric to find out if some parts of your code are coupled regarding their conjoint changes: Temporal Coupling.

In this and the next blog posts, I’m playing around with Adam’s ideas (and more) to find hidden dependencies of code parts based on version control data.

In this part, we just want to spot co-changing files which are files that change within the same commit.

As almost always, we are using Python and pandas for this analysis.

Data

With the help of a little helper library, we extract relevant log data from a Git repository. In this case, we are just using a synthetic repository to easier check that everything is working as expected.

Here are all files and all the commits from the repository:

In [1]:
from lib.ozapfdis.git_tc import log_numstat
commits = log_numstat("../../synthetic_repo//")
commits
Out[1]:
additions deletions file sha timestamp author
1 1.0 0.0 b a2abe69 2018-07-19 13:53:09 Markus Harrer
2 1.0 0.0 d a2abe69 2018-07-19 13:53:09 Markus Harrer
4 1.0 0.0 a f80a5af 2018-07-19 13:52:48 Markus Harrer
5 1.0 0.0 b f80a5af 2018-07-19 13:52:48 Markus Harrer
7 0.0 0.0 e fcf1498 2018-07-19 13:52:31 Markus Harrer
9 1.0 0.0 b 7e6d738 2018-07-19 13:52:10 Markus Harrer
10 1.0 0.0 d 7e6d738 2018-07-19 13:52:10 Markus Harrer
12 0.0 0.0 d 2b4d97d 2018-07-19 13:51:14 Markus Harrer
14 1.0 0.0 b 732ebbb 2018-07-19 10:51:03 Markus Harrer
15 1.0 0.0 c 732ebbb 2018-07-19 10:51:03 Markus Harrer
17 1.0 0.0 a 72f5268 2018-07-19 10:50:49 Markus Harrer
18 1.0 0.0 b 72f5268 2018-07-19 10:50:49 Markus Harrer
20 2.0 0.0 a f3c99c6 2018-07-19 10:50:38 Markus Harrer
21 1.0 0.0 b f3c99c6 2018-07-19 10:50:38 Markus Harrer
23 0.0 0.0 c 5d5fba5 2018-07-19 10:50:13 Markus Harrer
25 0.0 0.0 a eb668d1 2018-07-19 10:49:16 Markus Harrer
26 0.0 0.0 b eb668d1 2018-07-19 10:49:16 Markus Harrer

We see that some files change often together (like “a” and “b” or “b” and “d”) and some files are completely changing alone (like “e”).

Let’s get rid of all the unneeded columns first by just the columns that we really need for this analysis.

In [2]:
commits = commits[['file', 'sha']]
commits.head()
Out[2]:
file sha
1 b a2abe69
2 d a2abe69
4 a f80a5af
5 b f80a5af
7 e fcf1498

Idea

In this analysis, we need to create a relationship from each changed file to all changed file within the same commit.

I tried different things there with various data transformations, but in the end, the following stupid straightforward approach worked best: We just assign to each file in a commit all files of the same commit and count the occurrence of these relationships.

This gives us the perspectives on co-working changes that we want.

Analysis

To implement the idea of above, we can use the pd.merge command of pandas to combine the commits DataFrame with itself. The key here is to use an outer join to expand each file in a commit (designated by the value sha) to all the files of a commit (again, designated by the values in sha).

In [3]:
import pandas as pd

commit_counts = pd.merge(
    commits,
    commits,
    left_on='sha',
    right_on='sha',
    suffixes=['','_other'],
    how='outer')
commit_counts.head()