Git的diff算法经常将显然与人类(可以理解代码)分开的更改弄乱。例如
def method_that_already_existed(blah)
a line that did not change
a line that was deleted ######## the changed area starts here (per Git)
a new line
end
def a newly_added_method_that_belongs_in_its_own_commit
blah blah blah
blah blah blah
etc. ######## the changed area ends here (per Git)
end
对于人类来说,显而易见的是,第一种方法和全新方法的更改是完全不同的更改。但是Git将它们视为一个,并且不允许我在任何情况下拆分它们。
更糟糕的是,更改(根据Git)从第一种方法的中间到第二种方法的结束之前。这样就不可能只选择特定的行并提交其中一种方法。那些git视为“上下文”的行是无法选择的。
如果我使用git add -p ./path/to/file
,则在我的Git版本中它不再具有s
选项(无论如何都无法正常工作),但是它具有e
可以编辑,但是不允许添加第二种方法的最后end
。因此,基本上,Git绝对无法为我提供智能选择更改并将它们分别添加到单独提交中的方法。
就像在VS Code中一样,我可以从现有行中逐行选择,但是我不能选择Git认为不属于更改区域的行。 (而且我也无法区分添加的行和删除的行-更改会无形地包含已删除的行,因此,如果它们实际上是其他更改的一部分,那么我再碰运气了。)
所以我无法找到控制它的方法,除非更改代码只是为了欺骗Git做正确的事 。如果我深入历史记录以获取在第一种方法中删除的行并将其重新添加回去,然后(临时)删除添加的行并保存文件,那么它将正确地识别出已更改的内容。当然,我必须记住撤消此繁琐的解决方案,并确保正确撤消它,否则我已经破坏了我的代码。这是一个乏味且非常可怕的解决方法。
如果有一种方法可以让Git像人类一样“正确地”识别变化,我会喜欢的。在我们有了基于AST的差异算法之前,我不希望很快就能使用这种算法。因此,下一件最好的事情是拥有一种方法来指定 发生了什么变化 ,而不是让Git来猜测。有什么办法吗?
例如(这只是部分解决问题的一种方式),如果我可以告诉Git永远不要让diff块跨越一个空行,那么我将解决这个特定示例。如果我有一个想要跨越一个空行的块,我很乐意将两个块分别添加。 Git应该 始终 将它们视为不同的更改。但这只是一个例子,不是基本问题。
基本问题是:
如果Git无法正确识别已更改的内容,如何强制它接受我已更改的版本? (无需诉诸繁琐且容易出错的操作,例如通过挖掘git历史记录来撤消其中一项更改来手动撤消某些更改,这样就不会将两个单独的内容错误地组合在一起!)