Python社区  »  Git

实用:Git 中的一些常见错误

进击的Coder • 6 月前 • 157 次点击  

转载来源

公众号:论智

来源:Aditya Sridhar

阅读本文大概需要 6 分钟。


无论是数据科学家、算法工程师还是普通开发人员,在每个团队协作开发任务中,Git 都是必不可少的版本控制工具,因此掌握它的基本操作十分有必要。但即便是教程满天飞的今天,开发人员在使用 Git 时也还是会犯一些不应该犯的错误。本文总结了其中的几种常见错误,希望能对新手有所帮助。

force push

有时,我们会需要用 force push 把 commit 推送到远端仓库。

  1. 假设有 2 名开发人员正在合作开发一个分支

  2. 之前开发人员1已经完成更改,把代码 push 到了远程仓库

  3. 现在,开发人员 2 也完成了更改,正当他准备提交时,他却发现自己无法将代码推送到远程仓库

  4. 由于开发人员 2 是个初学者,他 Google 了一下,发现了一个神奇的命令 git push -f,于是进行了强制 push

  5. 之后开发人员 1 在检查远程仓库时,发现自己编写的代码全消失了

出现这个问题的原因是 force push 会覆盖远程仓库中的代码,使现有代码全部丢失。

如果开发人员 2 想避免这个问题,一种理想方法是他先把开发人员 1 的更新从远程仓库 pull 到本地,然后把自己的代码 rebase 一下,再进行 push。这里我们讨论的是在同一分支中从远程到本地仓库的 rebase。

git push -f 这个命令非常不安全,除非有绝对的必要,大家最好还是不要用它。它会把本地分支的提交覆盖远程推送分支的提交,给协作的同伴带去不少麻烦,即便是上面的解决方案,它也可能存在一个时间差的问题,因为你不可能时刻掌握同伴的工作进展。

所以如果大家都用正确的 git 工作流,让每个开发人员都拥有自己的功能分支,这种情况根本不会发生。

Rebase

如果你想把一个分支的修改合并到当前分支,你可以用 git rebase。它和 git merge 的区别是 merge 有一个合并 commit 的步骤,而 rebase 是把所有 commit 都串联在一起,让你本地的分支历史看起来像没有经过任何合并一样。

  1. 假设有 2 名开发人员正在合作开发一个功能分支

  2. 开发人员 1 率先完成了一系列 commit,并将其推送到远程功能分支

  3. 之后,开发人员 2 把远程功能分支的最新更改 pull 到本地

  4. 开发人员 2 向本地功能分支添加了一堆 commit

  5. 这时,他想把本地仓库的更新重新 rebase 到远程仓库中,于是他把整个预发分支(release branch)在本地功能分支上 rebase 了一下。这里我们讨论的是在不同分支中从远程到本地仓库的 rebase

  6. 现在,开发人员 2 试着把代码 push 到远程功能分支上,由于提交历史记录已更改,这个操作不被允许,他只能又开始用 git push -f

  7. 最后,当开发人员 1 想从远程仓库提取最新代码时,由于提交记录已更改,他被迫需要处理大量代码冲突问题

常规rebase

开发人员2的操作

如上图所示,rebase远程仓库会改变提交历史记录,并在其他开发人员尝试从远程仓库中提取最新代码时产生问题。处理这种情况的理想方法是始终只rebase本地仓库,本地仓库中的任何commit都不应该被push到远程仓库。

如果别人事先已经把commit推送到远程功能分支,那么你最好先用pull命令把更新拉到本地,用merge和你的修改合并,因为merge不会改变提交历史,而rebase会。

此外,和上个问题一样,如果使用正确的git工作流,每个开发人员都会有自己的功能分支,这时,开发者在自己的功能分支上进行更新并且在远程功能分支上做rebase是不会报错的,因为没有其他开发人员从同一个远程功能分支中提取代码。无论如何,尽量避免重新定义远程仓库。

Rebase是一个非常强大的功能,使用时也需谨慎。

amend

git amend 命令的作用是修复最近一次 commit,让你合并你缓存区的修改和上一次 commit,而不是提交一个新的快照。这里需要注意一点,它不是修改最近一次 commit,而是整个替换掉原 commit,所以对 Git 来说这是一个新的 commit。此外,它还可以用来编辑上一次的 commit 描述。

  1. 假设有 2 名开发人员正在合作开发一个功能分支

  2. 开发人员 1 率先完成了 commit,并将其推送到远程功能分支,我们把它称为“old commit”

  3. 之后,开发人员 2 把最新代码从远程功能分支 pull 到本地功能分支

  4. 然后他开始处理本地仓库中的代码,在这个过程中,他没有向远程仓库 push 任何 commit

  5. 这时开发人员 1 突然发现之前的 commit 中存在 bug,他用 amend 命令修复了本地仓库里的最近一次 commit,我们把它称为“new commit”

  6. 开发人员 1 尝试把这个新 commit 重新 push 到远程功能分支,由于提交历史记录发生了变化,这个操作报错了,于是他调用了 git push -f

  7. 现在,当开发人员 2 想从远程功能分支中提取最新代码时,git 会注意到提交历史记录的变化并创建合并的 commit。因此当他 pull 到本地后,他会在本地仓库里发现“commit old”和“commit new”,这就破坏了 amend 这个操作的意义。

  8. 最后,即便开发人员 2 从远程分支到本地分支执行 rebase,这个“commit old”还是会出现在本地仓库中,它仍然会作为历史提交的一部分。

amend commit 会更改提交历史记录,所以当其他开发人员尝试从远程仓库提取最新代码时,修改远程仓库中的 commit 会产生混淆。

为了避免这个错误,最好的方法是只在本地仓库里修改 commit,不要对远程库里的 commit 做任何修改。当然,一人一个分支也不会出现这个问题。

Hard reset

git reset 命令是用来将当前 branch 重置到另外一个 commit 的。它不会产生 commit,而是只更新一个 branch(branch 本身就是一个指向一个 commit 的指针)指向另外一个 commit。

  1. Hard reset 的命令是 git reset --hard

  2. 此外,git reset 还有 --soft 和 --mixed,只不过它们都没有 Hard reset 那么不安全

  3. 假设开发人员 1 正在开发一个功能分支,并在本地仓库中完成了 5 次 commit

  4. 与此同时,他还正在处理尚未提交的两个文件

  5. 这时,如果他运行了 git reset --hard

  6. 那么功能分支中的最新 commit 会变成是 commit4,commit5 丢失

  7. 同时他正在处理的那两个未提交文件也会丢失

这时 commit5 还在 git 内部,只不过对它的引用丢失了,我们可以用 git reflog 把它恢复,但总体来说,hard reset 还是很不安全。在 git 中使用 reset 命令时要非常小心,如果必须得用,确保你已经完全评估所有情况。

小结

综上所述,为了避免使用 git 时出错,我们可以牢记这几条教训:

  1. 避免多人在同一分支上协作。上述四个例子中有三个都是在说明这个问题,在日常工作中,遵守正确的工作流非常重要,要确保只有一个人在一个功能分支上工作,这是技术主管、高级开发人员尤其需要注意的。

  2. 不要到处实用 force push。

  3. 如果万不得已必须使用 force push,先评估其他方案,把它作为最后的手段。

  4. 不要试图修改远程仓库里的 commit,要只在本地仓库中更改 commit 历史记录。但即便是在本地仓库里,用 rebase 还是要谨慎。

原文地址:adityasridhar.com/posts/how-you-can-go-wrong-with-git


推荐阅读

1

跟繁琐的命令行说拜拜!Gerapy分布式爬虫管理框架来袭!

2

跟繁琐的模型说拜拜!深度学习脚手架 ModelZoo 来袭!

3

只会用Selenium爬网页?Appium爬App了解一下

4

妈妈再也不用担心爬虫被封号了!手把手教你搭建Cookies池


崔庆才

静觅博客博主,《Python3网络爬虫开发实战》作者

隐形字

个人公众号:进击的Coder

长按识别二维码关注

这里“阅读原文”,查看更多


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/oABWOCkEMm
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/27212
 
157 次点击  
分享到微博