I've read a lot about how git cleverly will detect when a file is renamed or moved, and you shouldn't have to (or can't) do anything to help it with that kind of task. Unfortunately we have a lot of issues in our project where the git history will consist of a single line after a file has been moved. Here is a pattern taken from a recent example I've seen:
Original class:
package a.b.c.d.e.f.X;
[four imports]
public interface A extends B {
void f(String id, int index) throws MyException;
@Annotation
class AImpl extends C implements A {
@OtherAnnotation
public void f(String id, int index)
throws MyException {
Map<String, Object> inputs = new HashMap<String, Object>();
inputs.put("a", id);
inputs.put("b", index);
execute(inputs);
}
@Override
public String g() {
return "xxxx.yyyy";
}
}
}
Class after being moved:
package a.b.c.d.e.f.Y;
[six imports, two new compared to original]
public interface A extends B {
void f(MyIdObject idobject, int index) throws MyException;
@Annotation
class AImpl extends D implements A {
@OtherAnnotation
public void f(@ParameterAnnotation([some stuff]) MyIdObject idobject, int index) throws MyException {
Map<String, Object> inputs = new HashMap<>();
inputs.put("c", idobject.getId());
inputs.put("b", index);
execute(inputs);
}
@Override
public String g() {
return "yyyy";
}
}
}
To summarize: class file was moved to another directory/package (differing by one level - see the package names), imports were added, a parameter was changed in the method that is declared and implemented here, a linebreak was removed in the method header, a string was changed inside the method, the HashMap instantiation was changed to use diamond notation, the return value in g() was changed.
Most identifiers and strings have been changed to protect the innocent - they're usually something like 10-20 characters. I haven't compiled this, so sorry if there are any mistakes - I hope you get the idea.
As this was part of some framework refactoring, there were a bunch of classes that were changed following this pattern, in the same commit, differing by string contents, amount of strings put in the hashmap, and the "f" method name.
So I think I can see what git is struggling with here - even though this particular rename is obvious by itself, when it's mixed in with other renames of files that have similar contents, git can't be sure which is which? Shouldn't the filenames (that weren't changed) be hint enough?
My impression is that, since git is supposed to handle this perfectly, there is no way to tweak git into handling this in a better way? Was there something we could have done when we refactored to make it work better? Is there something we can do now?
Especially: I want to be able to see the diff for a file in each commit, including the one where the rename was done. I am used to loading the git history in IntelliJ, and he double clicking one commit, which will show me changes were done in that commit. I get that it may not be possible to get what I want in IntelliJ, but how would I do it on the command line or elsewhere, for a file that has had its history interrupted like this?
Things that we probably don't want to do: 1) one commit for each rename, 2) one commit for renaming + another for content changing.
If you're curious about the Java design send me a PM - let's keep this thread about git. :)