Accurate Method and Variable Tracking in Commit History
Mehran Jodavi

Nikolaos Tsantalis

Concordia University
Canadam_jodavi@encs.concordia.ca

Concordia University
Canadanikolaos.tsantalis@concordia.ca

ABSTRACT
Tracking program elements in the commit history of a project isessential for supporting various software maintenance, comprehension and evolution tasks. Accuracy is of paramount importance forthe adoption of program element tracking tools by developers andresearchers. To this end, we propose CodeTracker, a refactoringaware tool that can generate the commit change history for method
and variable declarations with a very high accuracy. More specifically, CodeTracker has 99.9% precision and recall in method tracking, surpassing the previous state-of-the-art tool, CodeShovel, witha comparable execution time. CodeTracker is the first tool of its
kind that can track the change history of variables with 99.7% precision and 99.8% recall. To evaluate its accuracy in variable tracking,we extended the oracle created by Grund et al. for the evaluationof CodeShovel, with the complete change history of all 1345 variables and parameters declared in the 200 methods comprising theGrund et al. oracle. We make our tool and extended oracle publicly
available to enable the replication of our experiments and facilitate
future research on program element tracking techniques.

CCS CONCEPTS• Software and its engineering → Software maintenance tools;
Software configuration management and version control systems.

KEYWORDS
commit change history, refactoring-aware source code tracking
ACM Reference Format:
Mehran Jodavi and Nikolaos Tsantalis. 2022. Accurate Method and Variable
Tracking in Commit History. In Proceedings of the 30th ACM Joint European
Software Engineering Conference and Symposium on the Foundations of Software Engineering (ESEC/FSE ’22), November 14–18, 2022, Singapore, Singapore.
ACM, New York, NY, USA, 13 pages. https://doi.org/10.1145/3540250.3549079

1

INTRODUCTION

Developers routinely track code snippets in the commit history
to facilitate various software engineering tasks. Codoban et al. [6]surveyed 217 developers to find the motivations behind examining
software history. The most common reasons are to a) recover therationale behind a snippet of code, b) find the commits that introduced a bug, c) find who are the knowledgeable peers on certain
Permission to make digital or hard copies of all or part of this work for personal orclassroom use is granted without fee provided that copies are not made or distributedfor profit or commercial advantage and that copies bear this notice and the full citationon the first page. Copyrights for components of this work owned by others than theauthor(s) must be honored. Abstracting with credit is permitted. To copy otherwise, or
republish, to post on servers or to redistribute to lists, requires prior specific permission
and/or a fee. Request permissions from permissions@acm.org.
ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore© 2022 Copyright held by the owner/author(s). Publication rights licensed to ACM.
ACM ISBN 978-1-4503-9413-0/22/11. . . $15.00
https://doi.org/10.1145/3540250.3549079

modules and patterns, d) reverse engineer requirements from code,e) keep up with how the code state evolves, f) apply changes fromother branches into the main branch. The surveyed developers also
expressed some challenges with the usability of existing tools, suchas their inability to detect file moves and renames, and their difficult
configuration (e.g., setting up git bisect to find the commit that
introduced a bug).

1.1

Motivation

Grund et al. [14] conducted a survey with 42 professional softwaredevelopers and found that they prefer source code history information at the method/function and class level rather than the file level.
Moreover, the tools used by the developers to inspect code history,
such as git log and IntelliJ’s history feature, are unable to find thecommit that actually introduced a method and deal with complex
structural changes (e.g., method moves). LaToza and Myers [26]surveyed 179 professional software developers at Microsoft andasked them to list hard-to-answer questions that they had recently
asked about code. Among the collected responses, developers asked
about “Where was this variable last changed?” when debugging,“When, how, by whom, and why was this code changed or inserted?”when they want to find the code’s creation in history to understandits context and motivation, and finally “How has it changed overtime?” when they want to know the entire history of a block ofcode, rather than its most recent change. These findings motivate
the need for developing tools that can track change history at amore fined-grained level, focusing on specific program elements,
such as methods/functions and variables.
Accurate code snippet tracking is also essential in many areas ofsoftware engineering research. Alencar da Costa et al. [9] pointed
out that bug-inducing analysis algorithms (e.g., SZZ [23, 40, 48]) suffer from broken historical links due to file moves and renames. Thisfurther affects the results of defect prediction techniques and empirical studies investigating the characteristics of bug-introducingchanges, which rely on the original SZZ algorithm or its variants [36]. Shen et al. [37] showed that automatic source code merging tools often fail to track the changed program elements correctly
due to overlapping refactoring operations, and thus are unable toperform the auto-merging. The automatic migration of client software to newer library and framework versions, requires to track the
updated API program elements (i.e., methods and fields) from thesource to the target version, extract changes in the API signatures,
and adapt accordingly the API references in client’s code [8, 10, 20].
API program element tracking has been performed both at commit level [4, 5] and release level [28, 29]. However, fine-grained
program element tracking at commit level may be more accurate
than release level [3], as comparing directly two releases involves
significantly more noise from overlapping changes performed in
all commits between the two releases.

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

The inherent limitations of the line-based text diff and blame
tools, which are predominantly used in the aforementioned software engineering tasks, motivated researchers to develop techniques for tracking more accurately program elements, such as
methods/functions and classes, in the commit history of software
projects [12, 14–17, 27, 41, 42]. These techniques deal with changes
that modify the name/signature or location of a program element
and can cause a split in its history. Hora et al. [17] found that 25% ofclasses and methods have at least one untracked change (i.e., move,rename, extract, inline refactoring) in their histories. Despite thesignificant accuracy improvements brought by program element
tracking tools, they still have some limitations, which we discussin the next subsection.

1.2

Limitations of Current Tracking Tools

CodeShovel [14], is the most accurate tool for uncovering Javamethod histories to-date, as it produces complete and accurate
commit change histories for 90% of methods, including 97% of all
method changes. CodeShovel is partially refactoring-aware. It supports the tracking of methods with changes in their signature (e.g.,
method rename, parameter addition/deletion), methods whose parent file has been moved/renamed, and methods moved to anotherfile. However, our experiments have shown that it fails to track properly methods from which a significant part of their body has been
extracted to new methods, as it uses a 75% body similarity threshold to match modified methods, and thus erroneously matches
the original method with the extracted one. The same limitation
holds when methods with a relatively large body are inlined to thetracked methods. Our approach overcomes this limitation by being
fully refactoring-aware and detecting method extractions/inlines
from/to the tracked methods.
FinerGit [16] and Historage [15] create a finer-grained Git repository, in which each Java method exists in its own file, and takeadvantage of Git mechanisms to track changes on each individual
method’s corresponding file. FinerGit improves on the limited capability of Historage to track renamed or moved methods, especiallyfor small methods, by formatting each file to include a single token
from the corresponding method in each line. This formatting makes
Git’s line-based similarity computation mechanism more robust
in matching small methods, which have been renamed or moved.
Pre-processing an entire repository to place each method in its own
file, is computationally expensive and requires additional hard disk
space, which can be prohibitive, especially for large repositories
with many files and a long commit history. As a matter of fact,
Grund et al. [14] found that FinerGit ran out of memory or did notfinish pre-processing within 15 minutes for the four largest repositories in their validation data set. Moreover, this pre-processing
cost did not contribute an accuracy improvement, as the recall of
FinerGit was 65% compared to 90% of CodeShovel [14].
Kim et al. [42] proposed an approach to identify function mappings across revisions even when a function’s name changes. Theirapproach considers the similarity of the following factors: function
name, incoming and outgoing calls, signature, function body text
diff, complexity metrics and the results of two clone detection tools(CCFinder and MOSS). The computation of text diff and the execution of multiple clone detection tools may have a considerable cost,

Mehran Jodavi and Nikolaos Tsantalis

especially when there are many combinations of deleted and newly
added functions to be compared.
A common limitation of all aforementioned tools is that they
are designed to support only the tracking of methods, and cannot
be extended to support the tracking of other program elements,
such as variables and attributes, whose evolution is also interestingfor the developers. Several studies have shown that developers
frequently refactor variables and attributes, which makes theirtracking in the commit history challenging. Negara et al. [33] foundthat Rename Local Variable and Rename Field are among themost popular refactorings applied by developers. Negara et al. [34]surveyed 420 developers, who ranked Change Field Type as themost relevant and applicable transformation that they perform.
Ketkar et al. [22] found that developers who changed the type of avariable or attribute, they also renamed it in 55% of the examined
instances.
Godfrey and Zou [12] implemented a tool, named Beagle, thatcan detect structural changes like rename, move, split, and merge atfunction, file, and subsystem level. They rely on origin analysis todecide if a program entity is renamed or moved and a function callanalysis to discover merges and splits of program entities. Although
Beagle supports the tracking of program elements at different levelsof granularity (i.e., function, file, subsystem), it requires as input
two complete versions of a software system in order to extract static
relations between program entities (e.g., function calls), and calculate various metrics. This makes Beagle impractical for program
element tracking at commit level.
Steidl et al. [41] proposed an incremental origin analysis thatapplies some heuristics to find moved, renamed, split, and merged
source code files. In contrast to Beagle, their approach is commitbased and incrementally reconstructs the history based on clone
information and file name similarity. However, the proposed origin
analysis is limited to files and thus does not support the trackingof program elements, such as methods, variables and attributes.
Lee et al. [27] implemented a tool named Tempura, enabling code
completion and navigation to operate on multiple revisions of code
at a time. To support these features, Tempura pre-processes thecommit history of a Git repository, and for each added, modified,renamed, or deleted Java file extracts and records its API information (i.e., type, method, field declarations) indexed by the enclosing
type’s fully qualified name. Temporal navigation is performed bya simple index lookup to list the revisions in which the selected
program element changed. A major limitation of Tempura is thatit requires to pre-process and index the repository under analysis,
which can take several minutes, especially for large repositories.
Moreover, Tempura is not fully refactoring-aware, as it infers only
Class Rename and Move refactorings by leveraging Git’s file rename/move detection capability.
Hora et al. [17] introduced the concept of change graph to model
the evolution of classes, methods, and their related changes in thecommit history of a project, and study the phenomenon of untracked
changes. In this graph, each class or method is represented as anode, while each tracked or untracked change is represented asan edge between two nodes. However, Hora et al.’s change graphis limited in modelling only the evolution of classes and methods,
supports a limited number of refactoring types (5 class-level and 6
method-level refactorings), and uses RefDiff [39] for the detection

Accurate Method and Variable Tracking in Commit Historyof refactoring operations, which has inferior precision, recall andperformance than RefactoringMiner [45, 46]. Finally, the graphedges model only a small subset of refactoring operations, whileother kinds of changes, such as method body and signature changes
are omitted. Thus, Hora et al.’s change graph cannot be used to findall commits where a program element changed, i.e., the graph canprovide only the commits in which a program element is involved
in refactorings.
Summary: None of the currently available tools can track theevolution of fields and local variables. Moreover, the evolution
tracking of methods is limited, as commonly applied refactoringtypes, such as Extract Method, are not supported by thecurrently available tools. According to Negara et al. [33] andTsantalis et al. [45], Extract Method is the most commonly
applied refactoring on methods.

1.3

Contributions

Our solution offers some significant improvements over the previous state-of-the-art and novel contributions:(1) We fix all inaccuracies that we found in the oracle provided by
Grund et al. [14] including the evolution history of 200 methods.
Moreover, we extend this oracle by adding the evolution historyof 1345 variables declared in these methods.
(2) We support new kinds of program element changes, such as documentation and annotation changes, which are not supported
by CodeShovel [14] and other tools.
(3) We improve both precision and recall in method evolution tracking over the previous state-of-the-art, CodeShovel [14].
(4) We extend RefactoringMiner [45, 46] with heuristics for performing partial and incremental commit analysis in order toreduce the execution time. We show that the applied heuristics
achieve an execution time comparable to that of CodeShovel [14]without jeopardizing precision or recall.
(5) We propose the concept of evolution hooks as a way to model
the change history of methods extracted/inlined from/to thetracked method of interest, and link the change histories of
relevant program elements.
(6) We are the first to support the evolution tracking of variabledeclarations with 99.7% precision and 99.8% recall.

2

APPROACH

This section presents our approach for modelling and reconstructing the changes applied on program elements, such as method andvariable declarations, in the commit history of a project.

2.1

Program Element Identifier

Each program element 𝑒 is uniquely identified in the commit historyof a software repository with the following tuple:
𝐼𝑒 = (𝑉𝑒 , 𝐶𝑂𝑁𝑒 , 𝑆𝐼𝐺𝑒 )(1)
where 𝑉𝑒 is the version of 𝑒 corresponding to the SHA-1 Git commit
ID in which a change took place on 𝑒, 𝐶𝑂𝑁𝑒 is the signature of thecontainer in which 𝑒 belongs to, and 𝑆𝐼𝐺𝑒 is the signature of 𝑒.
The typical container structure in Java programs is shown in
the example of Figure 1. The container of a type declaration 𝑐 is

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore
Zull-core/src/main/java
package com.netflix.zull;
public class FilterProcessorImpl {protected final FilterLoader filterLoader;
protected ZuulFilter getErrorEndpoint(ZuulMessage msg) {SessionContext context = msg.getContext();
String endpointName = context.getErrorEndpoint();...
ZuulFilter errorEndpoint = getFilterByNameAndTyper(
endpointName, FilterType.ENDPOINT);
if(errorEndpoint == null) {String errorStr = "..." + endpointName;
LOG.error("..." + errorStr, context.getError());}
return errorEndpoint;}}

Figure 1: Typical container structure in Java programs
the tuple 𝐶𝑂𝑁𝑐 = (𝑆𝑅𝐶𝑐 , 𝑃𝐾𝐺𝑐 ), where 𝑆𝑅𝐶𝑐 is the source folder
path and 𝑃𝐾𝐺𝑐 is the package name in which 𝑐 belong to. It isvery important to include the source folder path in the container
tuple, as it is possible to have a type declaration with the same
name and package in two different source folders. The containerof a method declaration 𝑚 is the tuple 𝐶𝑂𝑁𝑚 = (𝐶𝑂𝑁𝐶𝑚 , 𝑆𝐼𝐺𝐶𝑚 ),where 𝐶𝑚 is the type declaration in which 𝑚 belong to, 𝐶𝑂𝑁𝐶𝑚 and
𝑆𝐼𝐺𝐶𝑚 are the container and signature of 𝐶𝑚 , respectively. Finally,
the container of a variable/parameter declaration 𝑣 is the tuple
𝐶𝑂𝑁 𝑣 = (𝐶𝑂𝑁𝑀𝑣 , 𝑆𝐼𝐺 𝑀𝑣 ), where 𝑀𝑣 is the method declarationin which 𝑣 is declared, 𝐶𝑂𝑁𝑀𝑣 and 𝑆𝐼𝐺 𝑀𝑣 are the container andsignature of 𝑀𝑣 , respectively.
The signature of a type/enum/annotation declaration 𝑐 is thetuple 𝑆𝐼𝐺𝑐 = (𝑁𝑐 , 𝐾𝑐 , 𝑆𝑐 , 𝐼𝑐 ,𝑇𝑐 , 𝐴𝑐 , 𝑉𝑐 , 𝑀𝑐 ), where 𝑁𝑐 is the name of𝑐, 𝐾𝑐 is the kind of 𝑐, which is a categorical variable taking four
possible values, namely class, interface, enum and @interface (forannotation type declarations), 𝑆𝑐 is the super-class type of 𝑐, 𝐼𝑐 is thelist of super-interfaces of 𝑐, 𝑇𝑐 is the list of type parameters of 𝑐 in
the case that 𝑐 is a parameterized type, 𝐴𝑐 is the list of annotationsof 𝑐, 𝑉𝑐 is the visibility of 𝑐, which is a categorical variable taking
four possible values (public, protected, private, or package-private),and finally 𝑀𝑐 is the list of modifiers of 𝑐 (final, static, abstract).
All elements in the signature of 𝑐 can change during its evolution,
including its kind 𝐾𝑐 .
The signature of a method declaration 𝑚 is the tuple 𝑆𝐼𝐺𝑚 =(𝑁𝑚 , 𝑅𝑚 , 𝑃𝑚 , 𝐸𝑚 ,𝑇𝑚 , 𝐴𝑚 , 𝑉𝑚 , 𝑀𝑚 , 𝐵𝑚 , 𝐷𝑚 ), where 𝑁𝑚 is the nameof 𝑚, 𝑅𝑚 is the return type of 𝑚, 𝑃𝑚 is the ordered parameter listof 𝑚, 𝐸𝑚 is the list of thrown exception types of 𝑚, 𝑇𝑚 is the list of
type parameters of 𝑚 in the case that 𝑚 is a parameterized method,
𝐴𝑚 is the list of annotations of 𝑚, 𝑉𝑚 is the visibility of 𝑚, 𝑀𝑚 isthe list of modifiers of 𝑚 (final, static, abstract, synchronized), 𝐵𝑚 isthe hashed value of 𝑚’s body string representation, and finally 𝐷𝑚
is the hashed value of 𝑚’s Javadoc and inline comments.
The signature of a variable/parameter declaration 𝑣 is the tuple
𝑆𝐼𝐺 𝑣 = (𝑁 𝑣 ,𝑇𝑣 , 𝐴𝑣 , 𝑀𝑣 , 𝑆 𝑣 ), where 𝑁 𝑣 , 𝑇𝑣 , 𝐴𝑣 , 𝑀𝑣 , 𝑆 𝑣 are the name,type, annotation list, modifier (i.e., final) and scope of 𝑣, respectively.
𝑆 𝑣 includes all statements 𝑣 is visible to, and thus 𝑣 can be referenced
from. The scope of a variable starts from the first statement following the declaration of the variable and ends to the last statement
within the block in which the variable is declared. Figure 1 depicts
the statements within the scopes of variables endpointName anderrorStr in the respective rectangular boxes. The scope is essential
for distinguishing variables with the same name and type declaredin different blocks of a method.

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

2.2

Mehran Jodavi and Nikolaos Tsantalis

Tracking Process

Our solution relies on RefactoringMiner [45] to track a program
element in the commit history of a project, and report all changes
and refactoring operations performed on it. Despite the fast execution time of RefactoringMiner (44 ms on median and 253 ms on
average per commit), running it on the entire commit history of
the project is computationally inefficient, as the tracked program
element is changing in a relatively small subset of commits, andfurthermore it is not always necessary to analyze all modified files
in a commit to track a single program element, especially in largecommits involving thousands of modified files. Therefore, we developed some heuristics and extended RefactoringMiner to performpartial and incremental commit analysis.
Input: Similarly to CodeShovel, our tool is using as input a Git
repository URL, a starting commit SHA-1 ID (or HEAD by default),
the file path containing the program element of interest, the nameof the program element, and the start line number of the program
element’s declaration. Both name and start line are needed to disambiguate the program element of interest, as it is possible to havemultiple program elements with the same name (i.e., overloaded
methods, identically named variables declared in different blocksof the same method), and it is possible to declare two or morevariables/parameters on the same line.
Output: A graph in which the nodes represent program elementswith their unique identifiers (i.e., program elements in different
commits), and each edge connecting two nodes includes the list ofchanges between the corresponding program elements. The edges
are directed from child commit program elements to the matching
parent commit program elements. In other words, by traversing theoutput graph, we visit previous versions of a program element (i.e.,backward tracking). We decided to model the output as a graph,because it is possible to have forks. For example, when multiple
methods from different subclasses are pulled up in a single superclass method, the same program element (i.e., superclass method) isconnected with multiple program elements (i.e., subclass methods).
In addition, we model extracted and inlined methods as branches
in the evolution graph of the main tracked program element, as
we will explain in Section 2.3. To facilitate the comparison with
CodeShovel [14], we can transform the graph output to a list ofcommits in which the input program element changed along withthe corresponding kinds of changes in each commit.

We adopted and extended the change hierarchy supported by
CodeShovel [14] for method tracking, as shown in Figure 2. The
newly supported change kinds are highlighted in blue colour, anddeal with InFileChange, i.e., the extraction of a new method fromthe body of the tracked method, and the inline of a method within
the body of the tracked method. In addition, we support two morekinds of changes, namely AnnotationChange, and DocumentationChange. The latter involves changes in the Javadoc or inline comments within the body of the tracked method. Finally, for somechange kinds we have a more fine-grained reporting. For example, CodeShovel reports any change(s) in the parameter list of amethod as a single ParameterChange, while we report individually for each parameter the following fine-grained changes, Add,
Remove, Rename, ChangeType, Merge, Split, and Reorder.
Figure 3 shows the change hierarchy supported by our tool forvariable tracking. InFileChange supports the scenario of a variabledeclaration being moved to another method in the same container,as part of a code fragment extracted to a new method or inlined
from a previously existing method, while CrossFileChange supports
the scenario of a variable declaration belonging to a method moved
to another container.
AbstractChange
Introduced

VariableChange

NoChange

VariableInFileChange

VariableCrossFileChange
VariableSignatureChange

InlinedFromMethod

VariableContainerChange

ExtractedToMethod
VariableTypeChange
VariableAnnotationChange

VariableRename

VariableModifierChange

Figure 3: Hierarchy of supported change kinds for variables.
An overview of the tracking process is shown in Figure 4 andconsists of the following steps:
Step #1
input
1.
2.
3.
4.
5.

git log --follow
filePath

Git repository URL
Start commit SHA-1
File path
Program element nameStart line number

For each commit r,
in which filePathchanged, locate e inparent commit p (ep)

Step #2
Using er signature as is
AbstractChange

Introduced

MethodChange

NoChange

Extracted
InFileChange

CrossFileChange

MethodSignatureChange

DocumentationChange
BodyChange

ExtractMethodFrom
InlineMethodTo

MethodMove

ExceptionChange

If at any step ep is
Step #3
located, skip all
Using er signature
subsequent steps
omi�ng method’s bodyand proceed withhashed value
the next commit.
If er is found as introduced
the process terminates.

ParameterChange

MethodContainerChange

MethodAccessModifierChange

Step #5b

Using RMiner to check
if er itself was moved toanother container

ReturnTypeChange
MethodModifierChange

MethodRename
MethodAnnotationChange

Figure 2: Hierarchy of supported change kinds for methods
adopted by CodeShovel [14]. Newly supported change kinds
are highlighted in blue colour.

Step #5a

Step #4

Using RMiner to check
if er container was
renamed or moved

Using RMiner to ﬁnd thebest matching methodwith signature changes

Figure 4: Overview of the tracking process steps.

Accurate Method and Variable Tracking in Commit History

Step #1: Given the input file path in which program element 𝑒 is located, we first find all commits in the project’s history in which file
path is modified using the command git log --follow filePath.
The --follow option is particularly important, as it continues listing the history of a file even when it gets renamed or moved. The
first step is based on the assumption that if there are no changes
in the file containing 𝑒 in a given commit, then we can skip theanalysis of this commit as 𝑒 has no changes too.
Step #2: For each commit 𝑟 in the subset of commits obtained from
Step #1, we create a partial source code model for 𝑟 and 𝑝 (i.e.,𝑟 ’s parent commit) by parsing only the source file corresponding
to the input file path. If 𝑟 is the starting commit, then we locate
program element 𝑒 in 𝑟 ’s model using its name and start line, andconstruct its signature (𝑠𝑖𝑔𝑒𝑟 ) and container (𝑐𝑜𝑛𝑒𝑟 ) as explained in
Section 2.1. If 𝑟 is a subsequent commit, then we have 𝑒𝑟 ’s signatureand container from the previous iteration of the tracking process(i.e., the matched program element from the previously processedcommit). Then, we attempt to locate a program element with thesame signature and container in 𝑝’s model. If a match is found,then we link the two program elements (𝑒𝑟 , 𝑒𝑝 ) with their unique
identifiers and report NoChange. Such a match is possible when
all containers of the tracked program element up to the root haveidentical signatures, but the file has changes in other irrelevant
parts. In such case, there is no need to execute RefactoringMiner.
If no match is found, we relax the comparison of signatures, as
explained in the next step.
Step #3: If program element 𝑒 itself or its container is a method(i.e., 𝑒 is a variable), then we omit 𝐵𝑚 (i.e., the hashed value of themethod’s body string representation) from the method’s signaturetuple, and we attempt to locate a program element with the same
relaxed signature and container in 𝑝’s model.
If a match is found and 𝑒 is a method, we link the two methods(𝑒𝑟 , 𝑒𝑝 ) with their unique identifiers and report BodyChange. Such amatch is possible when there are changes in the body of the tracked
method, but its signature remains unchanged. However, we stillneed to check if the tracked method is involved in an Extract
Method or Inline Method refactoring. To avoid an unnecessary
execution of RefactoringMiner, we extract all method calls from𝑒𝑟 and 𝑒𝑝 , respectively, and keep the calls that do not have a caller
expression or have this as a caller expression (i.e., the calls to local
methods). If there are additional calls in 𝑒𝑟 ’s call list, then we need tocheck if a local method was extracted from 𝑒𝑝 . If there are additionalcalls in 𝑒𝑝 ’s call list, then we need to check if a local method wasinlined to 𝑒𝑟 . In both cases, we execute RefactoringMiner on thepartial source code models for commits 𝑟 and 𝑝 including only
𝑇𝑟 (i.e., the type declaration containing 𝑒𝑟 ) and 𝑇𝑝 (i.e., the typedeclaration containing 𝑒𝑝 ). For each Extract Method or Inline
Method refactoring returned by RefactoringMiner, we introduce
the extracted/inlined program elements as evolution hooks in the
output graph (Section 2.3 includes more details). However, if thetwo method call lists are identical, then there is no need to execute
RefactoringMiner.
If a match is found and 𝑒 is a variable, we link the two variables(𝑒𝑟 , 𝑒𝑝 ) with their unique identifiers and report NoChange. Such amatch is possible when 𝑒𝑟 and 𝑒𝑝 still have the same name, type,modifier, annotations, and statements in their scopes, despite the

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

changes in the body of their container method. However, if nomatching variable is found, but the container methods 𝑐𝑜𝑛𝑒𝑟 and𝑐𝑜𝑛𝑒𝑝 are matched, we extract all variables declared within the
body of 𝑐𝑜𝑛𝑒𝑟 and 𝑐𝑜𝑛𝑒𝑝 and omit 𝑆 𝑣 (i.e., the list of statements
within the variable’s scope) from all variable signature tuples. If
the two lists of relaxed variable signatures are identical, then welink 𝑒𝑟 with the corresponding variable 𝑒𝑝 (i.e., the variable having
the same position in the list of variables declared within 𝑐𝑜𝑛𝑒𝑝 ).
Such a match is possible when 𝑒𝑟 and 𝑒𝑝 still have the same name,type, modifier, annotations, but there are some syntactic changes
in the statements within the scope of the variables. However, if
the two lists of relaxed variable signatures are not identical, thenwe execute RefactoringMiner on the partial source code models
for commits 𝑟 and 𝑝 including only 𝑇𝑟 (i.e., the type declaration
containing 𝑐𝑜𝑛𝑒𝑟 ) and𝑇𝑝 (i.e., the type declaration containing 𝑐𝑜𝑛𝑒𝑝 ).
RefactoringMiner will initially match the container methods 𝑐𝑜𝑛𝑒𝑟and 𝑐𝑜𝑛𝑒𝑝 and perform a thorough analysis after matching thestatements within their bodies, in order to find renamed, inlined,
extracted, split, merged, moved (due to method extraction or inline),
added, deleted, and matched variables. We locate 𝑒𝑟 in the reported
refactorings, link 𝑒𝑟 with the corresponding variable 𝑒𝑝 , and report
all changes found between them.
If by the end of Step #3 no match is found for 𝑒, this is an indication that there are major changes in the signature of 𝑒 itself or its
container. This scenario is addressed in the next step.
Step #4: Assuming that 𝑒𝑟 is contained within type declaration 𝑇𝑟
in commit 𝑟 , and exists a type declaration 𝑇𝑝 in commit 𝑝, where
both 𝑇𝑟 and 𝑇𝑝 have an identical name and container signature,then we attempt to locate 𝑒𝑝 within 𝑇𝑝 , by executing RefactoringMiner on the partial source code models including only 𝑇𝑟 and 𝑇𝑝 .
RefactoringMiner initially matches the method pairs with identicalsignatures (i.e., method name and parameter types), and then compares all combinations of the remaining unmatched methods from𝑇𝑟 with the remaining unmatched methods from 𝑇𝑝 to find the best
matching method pairs with changes in their signatures [45].
If 𝑒𝑟 is a method, we check if there exists a pair (𝑒𝑟 , 𝑒𝑝 ) in thebest matching method pairs. If so, we link the two methods (𝑒𝑟 , 𝑒𝑝 )with their unique identifiers and report all changes in their signatures and bodies. In addition, we add any local methods extracted
from 𝑒𝑝 or inlined to 𝑒𝑟 as evolution hooks in the output graph (Section 2.3), as this information is provided by RefactoringMiner whencomparing two type declarations.
If 𝑒𝑟 is a variable, we check if there exists a pair (𝑐𝑜𝑛𝑒𝑟 , 𝑐𝑜𝑛𝑒𝑝 )including the container of 𝑒𝑟 in the best matching method pairs. If
so, we retrieve all variable-related refactorings (i.e., rename, inline,
extract, split, merge, move, add, delete, and match) extracted by
RefactoringMiner for this pair of methods. We locate 𝑒𝑟 in thereported refactorings, link 𝑒𝑟 with the corresponding variable 𝑒𝑝 ,and report all changes found between them.
If by the end of Step #4 there is still no match found for program
element 𝑒, this is an indication that either 𝑒 itself or its container has
been moved to another file, or the type declaration 𝑇𝑟 containing
𝑒𝑟 has been renamed or moved to another package. This scenario
is addressed in the next and final step.
Step #5: At this stage, we keep the partial source code model including only 𝑇𝑟 for commit 𝑟 , but add all modified and removed files

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

in commit 𝑝 to 𝑝’s source code model (i.e., we create the complete
source code model for commit 𝑝). Then, we execute RefactoringMiner on these two source code models, and collect all reported
refactorings, including Rename Class, Move Class and Move
Method. Step #5 is the most time-consuming step in the tracking process, as we include all modified files in commit 𝑝. During
our experiments, we discovered some commits (e.g., in project
hadoop [30]) in which the developers moved thousands of sourcecode files from one source folder to another (i.e., the moved files
have a change in their file path, but their contents remain identical),or simply re-organized the import declarations (e.g., hibernateorm [47]), or updated comments, such as the license header (e.g.,
eclipse-jetty [11]). To avoid the unnecessary processing of files andspeed-up the tracking process, we exclude from 𝑝’s source code
model all files with identical contents, and files with only trivial
changes in comments and import declarations [21]. Finally, we support three scenarios in which additional files need to be included
in 𝑟 ’s source code model to correctly track program element 𝑒.
(1) Changes on 𝑒 can only be inferred from changes in otherprogram elements: RefactoringMiner infers signature-level refactorings for method pairs not having a body (i.e., interface or abstract methods), or method pairs that could not be matched basedon statement mapping information (i.e., methods with large differences in their bodies due to functionality changes) from therefactorings/changes detected on method pairs having identicalsignatures with the unmatched method pairs [45]. The intuition isthat a change in the signature of an abstract or interface methodshould propagate to all concrete implementations of that method(i.e., overriding methods). Assuming that 𝑒𝑟 is contained within
type declaration 𝑇𝑟 in commit 𝑟 , we get the extended superclassand implemented interface types of 𝑇𝑟 and check for each one ofthese types if it corresponds to a modified file in commit 𝑟 to ensure
the super type is a local type declaration of the analyzed system. If
a super type 𝑆𝑟 indeed corresponds to a modified file in commit 𝑟 ,then we use regular expressions to check if other modified files incommit 𝑟 extend or implement 𝑆𝑟 and add them to 𝑟 ’s source code
model. This approach enables the inference mechanism of RefactoringMiner with the least possible computation cost. For example,
in project OkHttp [49], the method pair synStream—headers in
inner class SpdyConnection.Reader is matched by additionally
including class MockSpdyPeer.InFrame to 𝑟 ’s source code model,
as both classes implement the FrameReader.Handler interface.
(2) 𝑒 is copied into a new file: In some projects, which are libraries with public APIs, we found that developers tend to copy themethods they want to deprecate into a new file, and then declarethe original methods or their container class as @deprecated. Let
us assume that 𝑒𝑟 is copied in type declaration 𝑇𝑟 in commit 𝑟 fromtype declaration 𝑇𝑝′ in commit 𝑝. Without additionally including
the original type declaration containing the copied method 𝑇𝑟′ to𝑟 ’s source code model, then 𝑒𝑟 would be detected as moved from 𝑇𝑝′
to 𝑇𝑟 , instead of introduced in 𝑇𝑟 as a new method. To address thisissue we use a regular expression to check if other modified files incommit 𝑟 include a @deprecated annotation with a @link to 𝑒𝑟 ’ssignature (e.g., copy methods copied from IOUtils to CopyUtils inproject commons-io [31]), or a @deprecated annotation with a reference to 𝑇𝑟 name (e.g., deprecated classes IOUtil and EndianUtil

Mehran Jodavi and Nikolaos Tsantalis

referring to newly added classes IOUtils and EndianUtils, respectively, in project commons-io [32]) and add them to 𝑟 ’s source code
model. Moreover, we check if other modified files in commit 𝑟 havethe same name as 𝑇𝑟 , but different package (e.g., methods copiedfrom deprecated class org.apache.commons.lang.NumberUtils
to new class org.apache.commons.lang.math.NumberUtils inproject commons-lang [7]) and add them to 𝑟 ’s source code model.
(3) 𝑒 is extracted to a new file: In this scenario, developers movesome members of an existing class into a new class, and instantiate
the new class into the origin class in order to access the moved
functionality (i.e., Extract Class refactoring), or extend the origin class in order to inherit the non-moved functionality (i.e., Extract Subclass refactoring). Let us assume that 𝑒𝑟 is moved in
type declaration 𝑇𝑟 in commit 𝑟 from type declaration 𝑇𝑝′ in commit 𝑝. Without additionally including the original type declaration containing the moved method 𝑇𝑟′ to 𝑟 ’s source code model,
then 𝑇𝑝′ would be detected as renamed to 𝑇𝑟 (if multiple members
from 𝑇𝑝′ have been moved to 𝑇𝑟 ), instead of 𝑇𝑟 being extracted
from 𝑇𝑝′ , and 𝑇𝑟′ being matched with 𝑇𝑝′ . To address this issue we
use a regular expression to check if other modified files in commit 𝑟 create an instance of 𝑇𝑟 (e.g., methods moved to extractedclass SourceFileInfoExtractor from class ProjectResolver inproject javaparser [43]), or are extended by 𝑇𝑟 (e.g., methods pushed
down to extracted subclass AbstractNestablePropertyAccessor
from origin class AbstractPropertyAccessor in project springframework [35]) and add them to 𝑟 ’s source code model.
Step #5a: Assuming that 𝑒𝑟 is contained within type declaration
𝑇𝑟 in commit 𝑟 , we check all class-related refactorings (i.e., rename,move class) to find a pair of type declarations (𝑇𝑟 , 𝑇𝑝 ) involving 𝑇𝑟 .
If such a pair is found, we obtain the corresponding class-level diffobject from RefactoringMiner, which includes all pairs of matchedmethods.
If 𝑒𝑟 is a method, then we check if there exists a pair (𝑒𝑟 , 𝑒𝑝 ) in
the matching method pairs. If so, we link the two methods (𝑒𝑟 , 𝑒𝑝 )with their unique identifiers, and report a FileMove change (i.e., 𝑇𝑟
is renamed/moved to 𝑇𝑝 ) in addition to any changes in their signatures and bodies. Moreover, we add any local methods extracted
from 𝑒𝑝 or inlined to 𝑒𝑟 as evolution hooks in the output graph (Section 2.3), as this information is provided by RefactoringMiner whencomparing two type declarations.
If 𝑒𝑟 is a variable, we check if there exists a pair (𝑐𝑜𝑛𝑒𝑟 , 𝑐𝑜𝑛𝑒𝑝 )including the container of 𝑒𝑟 in the matching method pairs. If so, we
retrieve all variable-related refactorings (i.e., rename, inline, extract,
split, merge, move, add, delete, and match) extracted by RefactoringMiner for this pair of methods. We locate 𝑒𝑟 in the reported
refactorings, link 𝑒𝑟 with the corresponding variable 𝑒𝑝 , and reporta MovedWithMethod change (i.e., 𝑐𝑜𝑛𝑒𝑟 has been relocated to 𝑐𝑜𝑛𝑒𝑝 )in addition to any changes found between the variables.
If by the end of Step #5a there is still no match found for program
element 𝑒, this is an indication that either 𝑒 itself or its container
has been moved to another file.
Step #5b: Assuming that 𝑒𝑟 is contained within type declaration
𝑇𝑟 in commit 𝑟 , we check all method-related refactorings involving
moves (i.e., move, pull up, push down method) to find a pair ofmethod declarations (𝑒𝑟 , 𝑒𝑝 ) if 𝑒𝑟 is a method, or (𝑐𝑜𝑛𝑒𝑟 , 𝑐𝑜𝑛𝑒𝑝 ) if

Accurate Method and Variable Tracking in Commit History

𝑒𝑟 is a variable, involving a move from 𝑇𝑟 . If such a pair is found,
we proceed in the same way as described in Step #5a with the only
difference being the report of a MethodMove change instead of a
FileMove (if 𝑒𝑟 is a method).
If by the end of Step #5b there is still no match found for program
element 𝑒, we report that 𝑒𝑟 has been Introduced in commit 𝑟 . We
further examine the refactorings reported by RefactoringMiner tofind if 𝑒𝑟 is introduced by an Extract Method refactoring, andadd the method(s) from which 𝑒𝑟 is extracted as evolution hooks inthe output graph (Section 2.3). If a matching program element 𝑒𝑝 isfound throughout Steps #2 to #5, we use its signature (𝑠𝑖𝑔𝑒𝑝 ) andcontainer (𝑐𝑜𝑛𝑒𝑝 ) to continue tracking program element 𝑒 in theremaining commits obtained from Step #1.

2.3

Change Graph Evolution Hooks

It is very likely that a developer would like to inspect the evolution of program elements which are extracted from or inlined
to the main tracked program element. The intuition behind thisfeature is that the extracted/inlined program elements were originally part or became part of the tracked program element at somepoint in its evolution. To support this feature our program element
tracking process (Section 2.2) introduces the extracted/inlined program elements as evolution hooks in the change graph of the main
tracked program element. The developer can attach on demand theevolution sub-graph of an extracted/inlined program element by
expanding the corresponding evolution hook.
Figure 5 shows how we model the evolution of an extracted
program element on the change graph of a tracked program element.
Assuming an Extract Method refactoring takes place in commit
𝑟 , then we create a node for the extracted element 𝑒𝑟′ with a unique
identifier 𝐼𝑒𝑟′ including the commit ID of 𝑟 , since 𝑒𝑟′ starts existingin commit 𝑟 , its signature (𝑠𝑖𝑔𝑒𝑟′ ) and container (𝑐𝑜𝑛𝑒𝑟′ ) constructed
as explained in Section 2.1. When the developer decides to expand
the 𝑒𝑟′ node, we use 𝐼𝑒𝑟′ and start commit 𝑟 as input for our tracking
process, which is executed forwards in this case (i.e., from parent
commit to child commit), and attach the resulting graph on the 𝑒𝑟′node, as shown in Figure 5.
evolu�on hook

tracked element evolu�oncommit r

extracted element evolu�on

ext
rac
ted
f

rom

the developer decides to expand the 𝑒𝑝′ node, we use 𝐼𝑒𝑝′ and startcommit 𝑝 as input for our tracking process, and attach the resulting
graph on the 𝑒𝑝′ node, as shown in Figure 6.
evolu�on hook

tracked element evolu�oninlined element evolu�onstart commit

commit p

er

ep

e
to
d
e

r

n

ep’ inli

Figure 6: Tracking of a program element inlined to thetracked element.
It is also very likely that a developer would like to inspect theevolution of the method(s) from which the tracked program element is extracted. Figure 7 shows how we model the evolution ofa program element, which is the origin of extraction for a tracked
program element. Assuming an Extract Method refactoring takes
place in commit 𝑟 , then we create a node for the origin element
𝑒𝑝′ with a unique identifier 𝐼𝑒𝑝′ including the commit ID of 𝑝 (i.e.,
the parent commit of 𝑟 ), since 𝑒𝑟 was originally contained in 𝑒𝑝′ incommit 𝑝, its signature (𝑠𝑖𝑔𝑒𝑝′ ) and container (𝑐𝑜𝑛𝑒𝑝′ ) constructed as
explained in Section 2.1. When the developer decides to expand the𝑒𝑝′ node, we use 𝐼𝑒𝑝′ and start commit 𝑝 as input for our tracking
process, and attach the resulting graph on the 𝑒𝑝′ node, as shownin Figure 7.
evolu�on hook

tracked element evolu�on

m

d
cte

fro

’
ep

origin element evolu�oncommit r

er

tra
ex

e p’

start

Introduced

e r’

Figure 7: Tracking of a program element from which the
tracked element is extracted.

start commiterep

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

ep er’

Figure 5: Tracking of a program element extracted from thetracked element.
Figure 6 shows how we model the evolution of an inlined program element on the change graph of a tracked program element.
Assuming an Inline Method refactoring takes place in commit
𝑟 , then we create a node for the inlined element 𝑒𝑝′ with a unique
identifier 𝐼𝑒𝑝′ including the commit ID of 𝑝 (i.e., the parent commit of 𝑟 ), since 𝑒𝑝′ last exists in commit 𝑝, its signature (𝑠𝑖𝑔𝑒𝑝′ ) andcontainer (𝑐𝑜𝑛𝑒𝑝′ ) constructed as explained in Section 2.1. When3

EVALUATIONIn our evaluation, we investigate the following research questions:
RQ1. What is the accuracy of CodeTracker in method tracking andhow does it compare to that of CodeShovel?
RQ2. What is the accuracy of CodeTracker in variable tracking?
RQ3. How does the execution time of CodeTracker compare tothat of CodeShovel?
RQ4. What is the execution time speedup of CodeTracker over thedefault operation mode of RefactoringMiner?

3.1

Oracle Update and Extension

Grund et al. [14] created an oracle with the change history of
200 methods from 20 popular open-source project repositories. In
particular, they used 100 of these methods (training set) to optimize
the threshold values used in CodeShovel, until they achieved 100%training accuracy, and the remaining 100 methods (testing set) toESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

validate the accuracy of CodeShovel. We decided to use both thetraining and testing sets to evaluate the accuracy of our tool andcompare with that of CodeShovel, since Grund et al. spent 100
hours of manual validations to construct their oracle, and thus we
can consider it as very reliable. However, after executing our tool
we found major differences in the commit history of some methods.
After careful inspection, we found out that 18 methods from thetraining set and 9 methods from the testing set were matched witha method extracted from their body at some point in their change
history. As a result, after the commit in which the the originally
tracked method is erroneously matched with an extracted one, theoracle includes the change history of the extracted method, insteadof the original method. In all these cases, a significant portion of
the originally tracked method (over 75%, or even the entire methodbody) is extracted to a new method. Silva et al. [38] found thatdevelopers in many cases extract a large portion or even the entire
body of a method into a new one, either to introduce an alternative
method signature (i.e., different input/output parameter types), or todeprecate a method that is no longer needed. The original method
remains in the code base and delegates to the extracted one inorder to preserve the public API (i.e., backwards compatibility).
Despite the strong similarity of the extracted method with theoriginal method, it is not correct to match them, as the original
method still remains in the code base with an identical signature(i.e., method name and parameter types) in most cases, and thus
should be further tracked. As we discussed in Section 2.3, we modelsuch cases as branches in the change graph of the tracked method
using evolution hooks, and continue tracking the changes on theoriginal method. Moreover, we found some cases where the oracle
reports a method being moved to another file (i.e., MethodMovechange), while in reality the type declaration that contains themethod has been renamed or moved, and thus a FileMove change isthe correct one.
We corrected all discrepancies found in the oracle by removing
the false change instances due to incorrect method matches andadding the new change instances resulting after the correction of
method matches. All removed and new change instances have been
manually validated by inspecting the changes on GitHub. Table 1
provides a detailed overview of the changes being common with theoriginal oracle (C columns), the changes removed from the original
oracle (R columns), and the new changes added to the original oracle(N columns) for both training and testing sets.
We further extended this oracle with the change history of thelocal variables and parameters declared in these 200 methods. Since
their number is large (967 variables in the training set and 378 variables in the testing set), we decided to follow a semi-automatedapproach to construct the oracle, instead of sampling a small number of variables and manually tracking their changes in the commit
history. We leverage information from the method tracking oracle,
as we know for sure that the commits in which a variable changed
is a subset of the commits in which its container method changed.
Next, for each variable, we execute our tool to perform backward
tracking on the commits in which the container method of thevariable changed. The output is a subset of these commits alongwith the changes found in each commit for the tracked variable.
There are two possible termination conditions:

Mehran Jodavi and Nikolaos Tsantalis

Table 1: Updates in the oracle created by Grund et al. [14]C: common R: removed N: newTraining set|

Testing set|

Change Kind

C

R

N | C

R

N |

Body Change
File Move
Parameter Change
Return Type Change
Modifier Change
Exception Change
RenameMethod Move
Introduced
Documentation Change
Annotation Change

2276
238
220
47
44
40
14
19
81
—
—

234
24
30
10
12
9
8
23
18
—
—

29
27
6
4
2
0
7
3
19
439
42

459
160
68
15
16
5
16
14
83
—
—

68
7
19
2
4
3
6
27
17
—
—

26
27
8
1
1
2
2
3
17
93
24

Total

2979

368

578

836

153

204

(1) The variable tracking reaches the commit in which the container
method was introduced. This means that the variable exists
since the introduction of its container method.
(2) The variable is introduced in a commit before reaching thecontainer method introduction commit. This means that thevariable was added as part of new functionality implemented
in the container method, or because some other method wasinlined to the container method.
We validate all reported changes by manually inspecting the corresponding commits. If a reported change is correct, we add it in
the oracle. If a reported change is incorrect, this means that there
was a wrong variable match performed by our tool. In that case,
we manually determine the correct match/change for the tracked
variable, add it in the oracle, and continue the tracking process fromthe parent commit for the correctly matched variable. This process
is repeated until we reach one of the two termination conditions foreach tracked variable. Reaching a termination condition guarantees
that we have no missing variable changes in our oracle. The numberof instances per change kind for the variables are shown in Table 2.
Table 2: Number of instances per change kind for variables.
Change Kind

3.2

Training set

Testing set

Introduced
RenameAnnotation Change
Type Change
Modifier Change

967
145
13
264
123

378
27
4
67
52

Total

1512

528

RQ1: Method Tracking Accuracy

The precision and recall of CodeTracker and CodeShovel was computed at two levels of granularity, namely commit level (i.e., finding
the commits in which a method changed), and change level (i.e., finding the kinds of changes that occurred in the commits in which amethod changed). When there are only changes in inline comments
within the body of a method, CodeShovel reports a BodyChange.

Accurate Method and Variable Tracking in Commit History

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

To ensure a fair comparison, we considered such cases as true positives, despite being labelled as DocumentationChange in the updated
oracle. Moreover, for any kind of change in the parameter list ofa method, CodeShovel reports a ParameterChange, while CodeTracker reports more fine-grained parameter changes, such as Add,
Remove, Rename, ChangeType, Merge, Split, Reorder, Add/Remove
Modifier, and Add/Remove/Modify Annotation. We also considered
the coarse-grained ParameterChange reports as true positives.
Table 3: Method tracking precision/recall at commit level
DatasetTool

TP

Training

CodeShovel 2751 219
CodeTracker 2825
1

74
0

92.63
99.96

97.38
100

Testing

CodeShovel
CodeTracker

65
0

91.94
100

92.27
100

Overall

CodeShovel 3527 287 139
CodeTracker 3664
1
0

92.48
99.97

96.21
100

776
839

FP

68
0

FN Precision Recall

method scenario in project javaparser [43], for which RefactoringMiner reports methods solve(Node) and solveField(Node) to be
moved from ProjectResolver to the same method solve(Node)in class SourceFileInfoExtractor. Although the reported moves
are technically correct, we considered one of them as the correctone, since our method evolution model supports only one-to-one
method mappings, similar to CodeShovel [14]. The remaining FPs
and FNs for CodeTracker are MoveMethod changes misreported as
FileMove by RefactoringMiner, because the child commit model did
not include the origin file of the method (i.e., the three heuristics
applied in Step #5 did not match the origin file of the method).
RQ1 finding: CodeTracker exhibits 99.9% precision and recall
at both commit and change levels. Compared to the previous
state-of-the-art tool, CodeTracker achieves an increase of +7.5%
in precision and +3.8% in recall at commit level, and an increaseof +9.1% in precision and +5.8% in recall at change level.

3.3

RQ2: Variable Tracking Accuracy

Based on the results shown in Table 3, our tool, CodeTracker,
has a consistent performance in both training and testing sets at
commit level, with an overall precision of 99.97% and recall of 100%.
On the other hand, CodeShovel has a lower precision and recall
on the testing set compared to the training set, as the similarity
thresholds used internally by CodeShovel were optimized on the
training set. This is an inherent limitation of approaches relying oncode similarity thresholds, as it is very difficult to derive universal
threshold values that can work well for all projects, regardlessof their architectural style, application domain, and development
practices [45].

Table 5 shows the precision and recall of CodeTracker at commit
and change level. RefactoringMiner detects variable-related refactorings based on the AST node replacements found in the pairs ofmapped variable declaration statements/expressions between twocode fragments (i.e., the body of a method in the child and parent
commits). It further verifies the matched variable declaration pairs
by examining the presence of statement mappings referencing thepaired variables within the variable scopes. As a result, the FPs are
due to incorrect statement mappings, while the FNs are due to its
inability to match some statement pairs.

Table 4: Method tracking precision/recall at change level

Table 5: Variable tracking precision/recall for CodeTracker

TPFP

Dataset

Level

95.92
100

Training

Commit 1459
Change 1510

2
4

1
2

99.86
99.74

99.93
99.87

87.06
99.71

87.98
99.71

Testing

CommitChange

512
527

1
3

0
1

99.81
99.43

100
99.81

90.77
99.87

94.13
99.93

OverallCommit 1971
Change 2037

3
7

1
3

99.85
99.66

99.95
99.85

DatasetTool

FN Precision Recall

Training

CodeShovel 3412 304 145
CodeTracker 3557
3
0

91.82
99.92

Testing

CodeShovel
915 136 125
CodeTracker 1037
3
3Overall

CodeShovel 4327 440 270
CodeTracker 4594
6
3

Based on the results shown in Table 4, our tool, CodeTracker,
has a similar performance at change level as commit level, withan overall precision of 99.87% and recall of 99.93%. On the other
hand, at change level, CodeShovel has a decrease of around 2%
in both precision and recall compared to the commit level results.
The FPs and FNs of CodeShovel are mainly due to mismatching
18 methods from the training set and 9 methods from the testing
set with a method extracted from their body at some point in theirchange history. As a result, the majority of the FPs are body andsignature changes found in the history of these 27 mismatched
extracted methods, while the majority of the FNs are body andsignature changes missed from the remaining history of the 27
original methods, in addition to missed changes in method annotations and Javadoc, which are not supported by CodeShovel.
The 3 FPs for CodeTracker in the training set are due to a merge

TP FP FN Precision Recall

For example, in project JavaParser [44], variable parent is erroneously matched with variable variableDeclarator in the parent
commit (false positive), because the initializers of the two variabledeclarations are identical, despite having a different type and name.
However, variable parent is extracted as a temporary variable fromvariableDeclarator’s initializer in the child commit, in order tothrow an exception if the parent reference is not an instance of the
VariableDeclarator type. Therefore, variable parent is a newly
introduced variable, and the pair of variableDeclarator variables
is not matched (false negative). Although RefactoringMiner is able
to detect Extract Variable refactorings, this particular instance
was missed. In project Hadoop [13], variable resourceSecondsMap
is erroneously matched with variable memorySeconds in the parent
commit (false positive), instead of being detected as a newly introduced variable (false negative). However, the developer merged

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

Mehran Jodavi and Nikolaos Tsantalis

two long variables, namely memorySeconds and vcoreSeconds
into the resourceSecondsMap, which is a map data structure withLong values.
RQ2 finding: CodeTracker exhibits 99.8% precision and 99.9%
recall at commit level, and 99.7% precision and 99.8% recall atchange level in tracking the change history of variables.

3.4

RQ3: Execution Time

Figure 8 shows the execution time of CodeTracker and CodeShovel
for tracking the entire change history of each method in the training
and testing sets, respectively (the y-axis is in logarithmic scale andthe units are in milliseconds). Each tool was executed separately
on the same machine with the following specifications: Intel Corei7-8565U CPU @ 1.80GHz × 8, 16 GB DDR3 memory, 512 GB SSD,
Ubuntu 20.04.2 LTS operating system, and Java 11.0.11 x64 with amaximum of 8GB Java heap memory (i.e., -Xmx8g). All 20 project
repositories from the training and testing sets were locally cloned
before running the tools. For each tool, we recorded the total time
taken for tracking a method in its entire commit change history,
including the time taken for parsing the source code files and detecting the changes on the tracked method in each commit, using the
System.nanoTime Java method. On median, CodeShovel processes
the commit change history of a method in 2 seconds, while our tool,
CodeTracker, takes 3.35 seconds (1.675 times slower). On average,
CodeShovel processes the commit change history of a method in 3.4
seconds, while CodeTracker takes 5.5 seconds (1.62 times slower).
However, CodeTracker has a more consistent performance between
the training and testing sets with similar median and average execution times. This consistent performance can be explained fromthe observation that CodeTracker has a slightly higher percentage
of commits reaching Step #5 (i.e., the most time consuming step of
the tracking process) in the testing set compared to the training set(6.13% vs. 4.24% as shown in Table 6), but at the same time has amuch higher percentage of commits whose processing completes in
Step #2 (i.e., the least time consuming step of the tracking process)in the testing set compared to the training set (82.33% vs. 67.52%
as shown in Table 6). In other words, the testing set includes morecommits in which the tracked method is moved or its container
type declaration is moved/renamed, but at the same time has much
more commits in which the tracked method remains unchanged.
Table 6: Average percentage of commits processed in eachstep of the tracking process.
DatasetStep #2

Step #3

Step #4

Step #5

Training

67.52%

24.21%

3.99%

4.24%

Testing

82.33%

8.66%

2.82%

6.13%

On the other hand, CodeShovel has a longer average execution
time on the testing set compared to the training set, despite thefact that the testing set has shorter commit change histories (34.5
and 47.5 commits on median and average, respectively) than the
training set (73 and 86.3 commits on median and average, respectively). More specifically, CodeShovel has a larger than 10 seconds
execution time for 10 methods of the testing set (8 of which arefrom project intellij-community), and only one method of the
training set. Typically, the methods with longer execution times
have multiple commits in which their container type declaration is
moved/renamed (CodeShovel’s phase 3), or the tracked method is
moved (CodeShovel’s phase 4). Both phases 3 and 4 are the mosttime consuming for CodeShovel, as it widens its search to consider
all other files that were modified in a commit.
RQ3 finding: Despite CodeTracker having a slower execution
time than CodeShovel (1.6 times on median and average), bothtools have execution times within the same order of magnitude.
The median and average execution time of CodeTracker is 3.35
and 5.5 seconds, respectively, which is acceptable given the considerably increased precision and recall over CodeShovel, theadditional computation of evolution hooks (Section 2.3), and theparallel tracking of the local variables and parameters declaredin the tracked method (i.e., CodeTracker can perform parallel
tracking of a method and its variable declarations without anadditional computational cost). The achieved execution time canwarrant applications in both research (e.g., large-scale MSR andsoftware evolution studies) and practice (e.g., blame-like tracking of method and variable change history within the context
of maintenance and program comprehension tasks).

3.5

RQ4: Speedup over RefactoringMiner

To evaluate the speedup achieved through steps 2–5 of our approach, we executed RefactoringMiner with its default operation
mode (i.e., with two complete source code models as input, including all modified/added files in commit 𝑟 and all modified/removed
files in commit 𝑝) right after step #1. The median execution timeof RefactoringMiner for tracking the entire change history of amethod was 8.76 and 12.29 seconds, while the average execution
time was 32.83 and 42.41 seconds on the training and testing sets,
respectively. Therefore, the speedup of our approach is between 2.6–
3.4 times on the median execution time, and between 5.9–7.8 times
on the average execution time. This is achieved without jeopardizing accuracy, as almost the same precision and recall is achieved inboth ways (with the exception of very few false positives/negatives
discussed in Section 3.2).
RQ4 finding: CodeTracker achieves a speedup of 2.6–3.4 times
on the median, and between 5.9–7.8 times on the average execution time over the default operation mode of RefactoringMiner
with a negligible effect on precision and recall. This shows thatthe heuristics applied throughout steps 2–5 are very effective.

4

LIMITATIONS AND THREATS TO VALIDITY

Language specificity: CodeTracker depends on RefactoringMiner
2.0 [45] for the detection of refactorings and changes on the tracked
program element, which limits its applicability to Java programs.
However, recently there have been efforts to extend RefactoringMiner for supporting other programming languages, e.g., Python [1,2] and Kotlin [24, 25]. With respect to CodeTracker, supporting another language would simply require to adjust the program element
signature definitions and the regular expressions used in Step #5 tothe characteristics and structure of this particular language.

Accurate Method and Variable Tracking in Commit History
100k

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

Max = 73158

Max = 73158
Max = 38356

Max = 31654

Max = 31654

Max = 14380

10k

Mean = 5532.00
Median = 3307.0

Mean = 5427.73
Median = 3642.0

Mean = 2990.77
Median = 1998.5

Mean = 5479.86
Median = 3354.0

Mean = 3871.05

Mean = 3430.91
Median = 1998.0

Median = 1998.0

1000

100
Tracker_train

Shovel_train

Tracker_test

Shovel_test

Tracker_all

Shovel_all

Figure 8: Execution time in milliseconds of CodeTracker and CodeShovel on training and testing sets.
Internal validity: The main threat to the internal validity is related
to the construction of the oracle used for evaluating the precisionand recall. To mitigate this threat we relied on an existing oracle,
which was constructed by Grund et al. [14] after manually validating the change history for 200 methods (100 hours of validation).
We further corrected all discrepancies found in the oracle caused by
27 methods (18 from the training and 9 from the testing set) being
mismatched with a method extracted from their body, by manuallyinspecting and validating all new change instances that resulted
after correcting the method matches. Moreover, we validated andadded two new kinds of method changes (i.e., annotation and documentation changes) that were not previously supported. Based on
the updated (and highly reliable) method history oracle, we constructed the change history of the variables declared in the bodyof these 200 methods following a semi-automated approach, as explained in Section 3.1, and manually inspecting all change instances.
Overall, the manual validation effort for correcting and extending
the Grund et al. oracle was approximately two person-months.
External validity: Our experiments were conducted on a relatively
small dataset including the change history of 200 methods from 20
different open source projects (i.e., 10 methods from each project),which might affected the generalizability of our findings. However,
we decided to rely on the same dataset used for the evaluation of
CodeShovel [14] to ensure a fair comparison between the two tools.
Moreover, constructing an oracle from scratch with methods fromother projects would involve a lot of manual effort and probably
include more errors from incorrect validations. On the other hand,
our extended oracle was essentially validated by two independent
research groups, which makes it more reliable.
Regarding change kinds, we considered all possible changes thatcan be performed on method and variable declarations with the
exception of changes in the initializer of variables, as the numberof changes for this particular kind was very large, and manuallyinspecting all of them was prohibitive.

5

CONCLUSIONS AND FUTURE WORKIn summary, the main conclusions and lessons learned are:(1) CodeTracker has high accuracy in tracking both methods (99.9%
precision/recall) and variables (99.7% precision, 99.8% recall).
(2) The proposed heuristics for setting up RefactoringMiner toperform partial commit analysis, resulted in an execution timecomparable to that of CodeShovel (i.e., CodeTracker is slower
by 1.67 times on median and 1.62 times on average).

(3) The speedup over the default operation mode of RefactoringMiner is 2.6–3.4 times on the median, and between 5.9–7.8
times on the average execution time. Despite this considerable
speedup, almost the same precision and recall is achieved in bothways with the exception of very few false positives/negatives.
A natural extension for CodeTracker is to support attribute tracking, since RefactoringMiner detects attribute-related refactorings ina similar way as variable-related refactorings. Furthermore, given
the remarkable performance of RefactoringMiner in variable tracking (i.e., mapping variable declaration statements), we are confident
that a similar approach for tracking code blocks (e.g., loops, trycatch blocks) would be also effective. RefactoringMiner applies abottom-up statement mapping process, where it first matches theleaf statements (i.e., statements without a body) and then uses thisinformation to match the parent composite statements (i.e., statements with a body). This approach leads to more accurate composite statement mappings. Moreover, RefactoringMiner supports the
mapping of traditional for loops and if conditionals to Java Stream
API calls (e.g., forEach(), map(), filter(), collect()), and traditional try-catch blocks with the newer try-with-resources
statement. This would allow to track the commit change history ofloops and try-catch blocks, even if they have evolved into newer
language constructs. Since developers are interested in the change
history of methods [14], it would make sense to provide morefine-grained historical information about specific code blocks withchanges in their body and conditional expressions.
Finally, we plan to conduct a usability study with professional
developers by providing CodeTracker’s functionality as an IDE
plugin (the tool is currently available as a Java library). It is particularly interesting to investigate under which maintenance scenarios
developers find the tool useful, and what kind of historical information (e.g., the kind of structural change, the author and time of
the change, the commit message and linked issues) they find more
relevant to their needs in each scenario.

6

DATA AVAILABILITY STATEMENT

We make the source code of CodeTracker and our oracle publicly
available [18, 19] to enable the replication of our experiments andfacilitate future research on program element tracking techniques.

ACKNOWLEDGMENTS
We would like to thank the anonymous reviewers for their insightful
and constructive feedback to improve the work. This research waspartially supported by NSERC grant RGPIN2018-05095.

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore

REFERENCES[1] Hassan Atwi, Bin Lin, Nikolaos Tsantalis, Yutaro Kashiwa, Yasutaka Kamei,
Naoyasu Ubayashi, Gabriele Bavota, and Michele Lanza. 2021. PyRef. https://github.com/PyRef/PyRef[2] Hassan Atwi, Bin Lin, Nikolaos Tsantalis, Yutaro Kashiwa, Yasutaka Kamei,
Naoyasu Ubayashi, Gabriele Bavota, and Michele Lanza. 2021. PyRef: Refactoring
Detection in Python Projects. In Proceedings of the 21st IEEE International Working
Conference on Source Code Analysis and Manipulation (SCAM 2021). 136–141.
https://doi.org/10.1109/SCAM52516.2021.00025[3] Aline Brito, Marco Tulio Valente, Laerte Xavier, and Andre Hora. 2020. You broke
my code: understanding the motivations for breaking changes in APIs. Empirical
Software Engineering 25 (2020), 1458–1492. https://doi.org/10.1007/s10664-01909756-z[4] Aline Brito, Laerte Xavier, Andre Hora, and Marco Tulio Valente. 2018. APIDiff:
Detecting API breaking changes. In IEEE 25th International Conference on Software
Analysis, Evolution and Reengineering (SANER ’18). IEEE Computer Society, Los
Alamitos, CA, USA, 507–511. https://doi.org/10.1109/SANER.2018.8330249[5] Aline Brito, Laerte Xavier, Andre Hora, and Marco Tulio Valente. 2018. Why andhow Java developers break APIs. In IEEE 25th International Conference on Software
Analysis, Evolution and Reengineering (SANER ’18). IEEE Computer Society, Los
Alamitos, CA, USA, 255–265. https://doi.org/10.1109/SANER.2018.8330214[6] Mihai Codoban, Sruti Srinivasa Ragavan, Danny Dig, and Brian Bailey. 2015.
Software History under the Lens: A Study on Why and How Developers Examine
It. In Proceedings of the 2015 IEEE International Conference on Software Maintenanceand Evolution (ICSME ’15). IEEE Computer Society, USA, 1–10. https://doi.org/
10.1109/ICSM.2015.7332446[7] Stephen Colebourne. 2021. Apache Commons-Lang. https://github.com/apache/commons-lang/commit/2d06a7ce8[8] Bradley E. Cossette and Robert J. Walker. 2012. Seeking the Ground Truth:
A Retroactive Study on the Evolution and Migration of Software Libraries. In
Proceedings of the ACM SIGSOFT 20th International Symposium on the Foundations of Software Engineering (Cary, North Carolina) (FSE ’12). Association
for Computing Machinery, New York, NY, USA, Article 55, 11 pages. https://doi.org/10.1145/2393596.2393661[9] Daniel Alencar da Costa, Shane McIntosh, Weiyi Shang, Uirá Kulesza, Roberta
Coelho, and Ahmed Hassan. 2017. A Framework for Evaluating the Results of
the SZZ Approach for Identifying Bug-Introducing Changes. IEEE Transactions
on Software Engineering 43, 7 (July 2017), 641–657. https://doi.org/10.1109/TSE.
2016.2616306[10] Danny Dig and Ralph Johnson. 2006. How Do APIs Evolve? A Story of Refactoring.
J. Softw. Maint. Evol. 18, 2 (March 2006), 83–107. https://doi.org/10.1002/smr.328[11] Joakim Erdfelt. 2021. Eclipse Jetty. https://github.com/eclipse/jetty.project/commit/41ed9f29f[12] Michael W. Godfrey and Lijie Zou. 2005. Using Origin Analysis to Detect Merging
and Splitting of Source Code Entities. IEEE Transactions on Software Engineering
31, 2 (Feb. 2005), 166–181. https://doi.org/10.1109/TSE.2005.28[13] Sunil Govindan. 2021.
Hadoop.
https://github.com/apache/
hadoop/commit/dae65f3bef8ffa34d02a37041f1dfdfeeee91845#diffd805bcb4a1f9cddb2b92a6b5982fc41beae91419c8a1252d71af9b65f6e3d43cR1005[14] Felix Grund, Shaiful Alam Chowdhury, Nick Bradley, Braxton Hall, and Reid
Holmes. 2021. CodeShovel: Constructing Method-Level Source Code Histories.
In 2021 IEEE/ACM 43rd International Conference on Software Engineering (ICSE)(ICSE ’21). 1510–1522. https://doi.org/10.1109/ICSE43902.2021.00135[15] Hideaki Hata, Osamu Mizuno, and Tohru Kikuno. 2011. Historage: Fine-Grained
Version Control System for Java. In Proceedings of the 12th International Workshop
on Principles of Software Evolution and the 7th Annual ERCIM Workshop on Software Evolution (Szeged, Hungary) (IWPSE-EVOL ’11). Association for Computing
Machinery, New York, NY, USA, 96–100. https://doi.org/10.1145/2024445.2024463[16] Yoshiki Higo, Shinpei Hayashi, and Shinji Kusumoto. 2020. On tracking Javamethods with Git mechanisms. Journal of Systems and Software 165 (2020), 110571.
https://doi.org/10.1016/j.jss.2020.110571[17] Andre Hora, Danilo Silva, Marco Tulio Valente, and Romain Robbes. 2018. Assessing the Threat of Untracked Changes in Software Evolution. In Proceedings ofthe 40th International Conference on Software Engineering (Gothenburg, Sweden)(ICSE ’18). Association for Computing Machinery, New York, NY, USA, 1102–1113.
https://doi.org/10.1145/3180155.3180212[18] Mehran Jodavi and Nikolaos Tsantalis. 2022. CodeTracker. https://doi.org/10.
5281/zenodo.7080276[19] Mehran Jodavi and Nikolaos Tsantalis. 2022. CodeTracker source code and oracle.
https://github.com/jodavimehran/code-tracker[20] Puneet Kapur, Bradley Cossette, and Robert J. Walker. 2010. Refactoring References for Library Migration. In Proceedings of the ACM International Conference on
Object Oriented Programming Systems Languages and Applications (Reno/Tahoe,
Nevada, USA) (OOPSLA ’10). Association for Computing Machinery, New York,NY, USA, 726–738. https://doi.org/10.1145/1869459.1869518

Mehran Jodavi and Nikolaos Tsantalis[21] David Kawrykow and Martin P. Robillard. 2011. Non-Essential Changes in Version
Histories. In Proceedings of the 33rd International Conference on Software Engineering (Waikiki, Honolulu, HI, USA) (ICSE ’11). Association for Computing Machinery, New York, NY, USA, 351–360. https://doi.org/10.1145/1985793.1985842[22] Ameya Ketkar, Nikolaos Tsantalis, and Danny Dig. 2020. Understanding Type
Changes in Java. In Proceedings of the 28th ACM Joint Meeting on European
Software Engineering Conference and Symposium on the Foundations of Software
Engineering (Virtual Event, USA) (ESEC/FSE 2020). Association for Computing Machinery, New York, NY, USA, 629–641. https://doi.org/10.1145/3368089.3409725[23] Sunghun Kim, Thomas Zimmermann, Kai Pan, and E. James Jr. Whitehead. 2006.
Automatic Identification of Bug-Introducing Changes. In 21st IEEE/ACM International Conference on Automated Software Engineering. IEEE Computer Society,
Washington, DC, USA, 81–90. https://doi.org/10.1109/ASE.2006.23[24] Zarina Kurbatova. 2021. KotlinRMiner. https://github.com/JetBrains-Research/
kotlinRMiner[25] Zarina Kurbatova, Vladimir Kovalenko, Ioana Savu, Bob Brockbernd, Dan Andreescu, Matei Anton, Roman Venediktov, Elena Tikhomirova, and Timofey
Bryksin. 2021. RefactorInsight: Enhancing IDE Representation of Changes in
Git with Refactorings Information. In 2021 36th IEEE/ACM International Conference on Automated Software Engineering (ASE 2021). IEEE Computer Society, Los
Alamitos, CA, USA, 1276–1280. https://doi.org/10.1109/ASE51524.2021.9678646[26] Thomas D. LaToza and Brad A. Myers. 2010. Hard-to-Answer Questions about
Code. In Workshop on Evaluation and Usability of Programming Languages andTools (Reno, Nevada) (PLATEAU ’10). Association for Computing Machinery, New
York, NY, USA, Article 8, 6 pages. https://doi.org/10.1145/1937117.1937125[27] Yun Young Lee, Darko Marinov, and Ralph E. Johnson. 2015. Tempura: Temporal
Dimension for IDEs. In 2015 IEEE/ACM 37th IEEE International Conference on
Software Engineering. 212–222. https://doi.org/10.1109/ICSE.2015.42[28] Mehran Mahmoudi and Sarah Nadi. 2018. The Android Update Problem: An
Empirical Study. In 15th International Conference on Mining Software Repositories(Gothenburg, Sweden) (MSR ’18). ACM, New York, NY, USA, 220–230. https://doi.org/10.1145/3196398.3196434[29] Tyler McDonnell, Baishakhi Ray, and Miryung Kim. 2013. An Empirical Study of
API Stability and Adoption in the Android Ecosystem. In IEEE International Conference on Software Maintenance (ICSM ’13). IEEE Computer Society, Washington,
DC, USA, 70–79. https://doi.org/10.1109/ICSM.2013.18[30] Arun C Murthy, Christopher Douglas, Devaraj Das, Greg Roelofs, Jeffrey Naisbitt,
Josh Wills, Jonathan Eagles, Krishna Ramachandran, Luke Lu, Mahadev Konar,
Robert Evans, Sharad Agarwal, Siddharth Seth, Thomas Graves, and Vinod Kumar
Vavilapalli. 2021. Hadoop. https://github.com/apache/hadoop/commit/dbecbe5df[31] Jeremias Märki. 2021. Apache Commons-IO.
https://github.com/apache/commons-io/commit/6a1bb4d53[32] Jeremias Märki. 2021. Apache Commons-IO.
https://github.com/apache/commons-io/commit/7748ed364[33] Stas Negara, Nicholas Chen, Mohsen Vakilian, Ralph E. Johnson, and Danny
Dig. 2013. A Comparative Study of Manual and Automated Refactorings. In
Proceedings of the 27th European Conference on Object-Oriented Programming(Montpellier, France) (ECOOP’13). Springer-Verlag, Berlin, Heidelberg, 552–576.
https://doi.org/10.1007/978-3-642-39038-8_23[34] Stas Negara, Mihai Codoban, Danny Dig, and Ralph E. Johnson. 2014. Mining
Fine-Grained Code Changes to Detect Unknown Change Patterns. In Proceedingsof the 36th International Conference on Software Engineering (Hyderabad, India)(ICSE 2014). Association for Computing Machinery, New York, NY, USA, 803–813.
https://doi.org/10.1145/2568225.2568317[35] Stéphane Nicoll. 2021. Spring Framework. https://github.com/spring-projects/
spring-framework/commit/2dc674f35[36] Giovanni Rosa, Luca Pascarella, Simone Scalabrino, Rosalia Tufano, Gabriele
Bavota, Michele Lanza, and Rocco Oliveto. 2021. Evaluating SZZ Implementations
Through a Developer-Informed Oracle. In Proceedings of the 43rd International
Conference on Software Engineering (Madrid, Spain) (ICSE ’21). IEEE Press, 436–447.
https://doi.org/10.1109/ICSE43902.2021.00049[37] Bo Shen, Wei Zhang, Haiyan Zhao, Guangtai Liang, Zhi Jin, and Qianxiang
Wang. 2019. IntelliMerge: A Refactoring-aware Software Merging Technique.
Proc. ACM Program. Lang. 3, OOPSLA, Article 170 (Oct. 2019), 28 pages. https://doi.org/10.1145/3360596[38] Danilo Silva, Nikolaos Tsantalis, and Marco Tulio Valente. 2016. Why We Refactor? Confessions of GitHub Contributors. In Proceedings of the 2016 24th ACM
SIGSOFT International Symposium on Foundations of Software Engineering (Seattle,
WA, USA) (FSE 2016). Association for Computing Machinery, New York, NY, USA,
858–870. https://doi.org/10.1145/2950290.2950305[39] Danilo Silva and Marco Tulio Valente. 2017. RefDiff: Detecting Refactorings in
Version Histories. In 14th International Conference on Mining Software Repositories(Buenos Aires, Argentina) (MSR ’17). IEEE Press, Piscataway, NJ, USA, 269–279.
https://doi.org/10.1109/MSR.2017.14[40] Jacek Śliwerski, Thomas Zimmermann, and Andreas Zeller. 2005. When Do
Changes Induce Fixes?. In International Workshop on Mining Software Repositories.
ACM, New York, NY, USA, 1–5. https://doi.org/10.1145/1082983.1083147

Accurate Method and Variable Tracking in Commit History[41] Daniela Steidl, Benjamin Hummel, and Elmar Juergens. 2014. Incremental Origin
Analysis of Source Code Files. In Proceedings of the 11th Working Conferenceon Mining Software Repositories (Hyderabad, India) (MSR 2014). Association for
Computing Machinery, New York, NY, USA, 42–51. https://doi.org/10.1145/
2597073.2597111[42] Sunghun Kim, Kai Pan, and E. J. Whitehead. 2005. When functions change theirnames: automatic detection of origin relationships. In 12th Working Conference on
Reverse Engineering (WCRE’05). 143–152. https://doi.org/10.1109/WCRE.2005.33[43] Federico Tomassetti. 2021. JavaParser. https://github.com/javaparser/javaparser/
commit/37f93be64[44] Federico Tomassetti. 2021. JavaParser.
https://github.com/javaparser/
javaparser/commit/427dd53b9ebedcb0bdb687007eb0faf2de734df4#diffd4545a64b742a6d7b072135d10643c1d309ecaa62daa9450ba05dc68985543aaR477

ESEC/FSE ’22, November 14–18, 2022, Singapore, Singapore[45] Nikolaos Tsantalis, Ameya Ketkar, and Danny Dig. 2022. RefactoringMiner
2.0. IEEE Transactions on Software Engineering 48, 3 (2022), 930–950. https://doi.org/10.1109/TSE.2020.3007722[46] Nikolaos Tsantalis, Matin Mansouri, Laleh M. Eshkevari, Davood Mazinanian,and Danny Dig. 2018. Accurate and Efficient Refactoring Detection in Commit
History. In Proceedings of the 40th International Conference on Software Engineering(Gothenburg, Sweden) (ICSE ’18). ACM, New York, NY, USA, 483–494. https://doi.org/10.1145/3180155.3180206[47] John Verhaeg. 2021. Hibernate ORM. https://github.com/hibernate/hibernateorm/commit/8c806d361[48] Chadd Williams and Jaime Spacco. 2008. SZZ Revisited: Verifying when Changes
Induce Fixes. In Workshop on Defects in Large Software Systems (Seattle, Washington). ACM, New York, NY, USA, 32–36. https://doi.org/10.1145/1390817.1390826[49] Jesse Wilson. 2021. OkHttp. https://github.com/square/okhttp/commit/a91124b6d