我对lint我的代码做了一些源更改。我没有运行单元测试,后来我发现一个大的提交破坏了代码。 如何返回并找出许多文件中的哪些代码更改导致测试失败?
我可以:
我希望git的手册不如此。
答案 0 :(得分:4)
使用git-stash
的能力不仅可以隐藏并重新应用更改,还可以使用索引的状态,这是一种不错的方法。它是这样的:
# check out the bad commit
git checkout bad-commit
# and then reset to the commit before, leaving the bad changes in the work tree
git reset HEAD^
# stage the things you want to keep/test first
git add -p
# stash away the rest (keep the staged parts)
git stash --keep-index
# now build/test. if it works, go ahead and commit it
git commit
# bring back the stashed changes
git stash pop
# repeat!
git add -p
git stash --keep-index
# now suppose the broken part is in what you kept, and you want to split it up more
# unstage the changes
git reset
# and then repeat!
git add -p
git stash --keep-index
# if you do this, you'll end up with multiple stashes; you can check on them:
git stash list
git stash show
git stash show -p stash@{1}
使用stashes和测试有一个好处,如果你设法选择一个只是破坏构建的更改的子集,你可以直接弹出存储,然后再试一次。
你可以做一些类似的事情,将提交分成多个,然后在其上运行git bisect
,但通常这样做更多,因为在你不进行测试的情况下,更难以知道如何拆分。
当然,现在您知道您应该进行较小的提交。但是我第一次也不总是这么做!
答案 1 :(得分:1)
您可以将提交拆分为几个小提交,然后使用git bisect
查找违规提交。最简单的方法是使用交互式rebase :
git checkout -b <name>
创建一个新分支,否则你就可以了。git rebase -i <bad commit>^
pick
更改为edit
,然后保存并关闭编辑器。git reset
,然后单独提交每个更改,将这个大型提交分成更小的提交。git rebase --continue
以完成rebase程序。您现在已将提交拆分为几个较小的提交,您可以更轻松地找出确切的更改。一种非常有效的方法是使用git bisect
。它的作用是执行提交的二进制搜索,以便准确找到被破坏的提交,这正是您想要实现的。这是你如何使用它:
git bisect start
。git bisect good <good commit>
,其中<good commit>
是一个哈希/标记/您知道有效的提交。您可以在刚刚进行的第一次拆分提交之前使用提交。git bisect bad <bad commit>
,其中<bad commit>
是一个has / tag /您认识不的任何提交。您可以使用HEAD
,因为您知道它已损坏。git bisect good
或git bisect bad
告诉git它是好还是坏。根据你的说法,Git将继续检查其他提交。git show <commit>
查看其中包含的内容。git bisect reset
退出平分模式。要了解有关这些主题的更多信息,请继续阅读:
git rebase --help
和git bisect --help
。答案 2 :(得分:1)
我最终基本上做了Jefromi所建议的。我写了这个python代码,命名为git-bisect.py:
#!/usr/bin/env python
from subprocess import Popen, PIPE
from sys import stderr
def run_command(cmd):
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
output, errors = p.communicate()
if p.returncode:
raise Exception(errors)
def process_all(filename):
with open(filename) as f:
all_files = [fn.strip() for fn in f]
try:
for i, f in enumerate(all_files, start=1):
print >> stderr, i, f
run_command(['git', 'add', f])
run_command(['git', 'stash', '--keep-index'])
run_command(['bin/login_test.sh'])
run_command(['git', 'stash', 'pop'])
except Exception, exc:
print >> stderr, exc
if __name__ == '__main__':
from sys import argv
for filename in argv[1:]:
process_all(filename)
并针对受影响的文件列表运行它。
这是我完整的工作流程:
# Get the commit just before things went bad
git checkout 8f5c3d7
# Diff good code against bad, make patch
git diff 8f5c3d7 cb8ddf0 > 8f5c3d7-cb8ddf0.patch
# Apply patch
git apply 8f5c3d7-cb8ddf0.patch
# Now my index has all the changes that went into the bad commit
# but with just a dirty index.
# Run code that finds bad file in commit
python ~/Dropbox/src/git-bisect.py ~/Dropbox/src/bad-commit.txt
然后它一直ch着直到它停在第一个坏文件上。然后我会:
git reset --hard HEAD
并重新应用补丁,将错误文件放在文件列表的末尾并重新开始。很快,我就知道有任何改变会破坏我的构建。