我的安全使用 Git push 命令的指南

2022年 7月 12日 124点热度 0人点赞 0条评论

file

引言

翻译和整理自: My guide to using the Git push command safely

了解这个流行的 Git 命令对您的项目的使用和影响, 学习新的更安全的替代方案, 并掌握恢复损坏分支的技能.

大多数人都知道 git push --force 是强烈建议不要使用 Git 的命令, 这会被认为具有破坏性.

然而, 对我来说, 在我的项目中完全信任 Git, 同时完全避免使用它的流行命令之一, 这似乎很奇怪.

这使我研究了为什么人们认为这个命令如此有害.

git 推送命令

要了解 Git 是如何工作的, 我们需要退后一步, 看看 Git 是如何存储数据的. 对于 Git, 一切都与提交有关. 提交是一个包含多个键的对象, 例如唯一 ID, 指向暂存内容快照的指针以及指向直接在该提交之前的提交的指针.

就此而言, 分支只不过是指向单个提交的指针.

git push 基本上是:

  1. 复制本地分支中存在的所有提交.
  2. 通过转发远程分支以引用新提交来集成历史记录, 也称为 Fast forward ref.

快进引用 (ref)

快进只是转发分支的当前提交引用. 当您推送更改时,Git 会自动搜索从当前 ref 到目标提交 ref 的线性路径.

如果祖先提交存在于远程而不是本地 (有人更新了远程, 而本地尚未更新), Git 将找不到提交之间的线性路径, 并且 git push 失败.

何时使用 --force

您可以使用 git rebase, git squashgit commit --amend 来更改提交历史记录并重写以前推送的提交. 但请注意, 我的朋友们, 这些强大的命令不只是改变提交——它们替换所有提交, 完全创建新的.

一个简单的 git push 失败, 你必须绕过"快进"规则.

输入 --force. 此选项覆盖"快进"限制并将我们的本地分支与远程分支匹配. 该 --force 标志允许您命令 Git 无论如何都要这样做.

当你更改历史记录, 或者当你想要推送与远程分支不一致的更改时, 你可以使用 push --force.

简单场景

假设 Lilly 和 Bob 是在同一个功能分支上工作的开发人员. 莉莉完成了她的任务并推动了她的改变. 过了一会儿, Bob 也完成了他的工作, 但在推送他的更改之前, 他注意到了一些添加的更改. 他执行了一个 rebase 以保持树清洁, 然后 push --force 将他的更改放到遥控器上. 不幸的是, 由于没有更新到远程分支, Bob 不小心删除了 Lilly 更改的所有记录.

Bob 在使用该 --force 选项时犯了一个常见错误. Bob 忘记更新 (git pull) 他的本地跟踪分支. 对于用户尚未更新的分支, 使用 --force 导致 Git 推送 Bob 的更改, 而不考虑远程跟踪分支的状态, 因此提交丢失. 当然, 你并没有失去一切, 团队可以采取措施恢复, 但如果不被发现, 这个错误可能会造成很大的麻烦.

替代方案: push --force-with-lease

--force 选项有一个不那么有名的亲戚, 称为 --force-with-lease, 它使您能够 push --force 在保证不会覆盖其他人的更改的情况下进行更改. 默认情况下, --force-with-lease 除非远程跟踪分支和远程分支指向同一个提交引用, 否则拒绝更新分支. 非常棒, 对吧? 它变得更好了.

您可以 --force-with-lease 准确指定要比较的提交, 分支或引用. 该 --force-with-lease 选项使您可以灵活地覆盖远程分支上的新提交, 同时保护您的旧提交历史. 这是同样的力量, 但有救生衣.

指南: 如何处理破坏性的 --force

毫无疑问, 你是一个负责任的开发人员, 但我敢打赌, 你或你的一个队友至少有一次发生过, 你或你的一个队友不小心碰到 git push --force 了一个任何人都不应该乱搞的重要分支. 转眼间, 大家的最新作品就丢失了.

无需恐慌! 如果你很幸运, 在你破坏它之前, 其他人在处理相同的代码之前提取了一个最新版本的分支. 如果是这样, 您所要做的就是询问他们 --force push 最近的变化!

但即使你没有那么幸运, 你仍然很幸运能找到这篇文章.

你是在犯错前最后一个推手的人吗?

首先, 不要关闭您的终端.

其次, 去找你的队友认罪.

最后, 确保在接下来的几分钟内没有人弄乱 repo, 因为你还有一些工作要做.

回到你的终端. 在终端的命令输出中 git push --force , 查找与此类似的行:

+ d02c26f…f00f00ba [branchName] -> [branchName] (forced update)

第一组符号 (看起来像提交 SHA 前缀) 是解决此问题的关键.

假设您在造成损害之前对分支的最后一次良好提交是 d02c26f. 您唯一的选择是用火攻克, 并将 push --force 此提交返回到坏分支之上的分支:

$ git push — force origin deadbeef:[branchName]

恭喜! 你拯救了这一天!

我不小心使用了--force push到我的 repo, 我想回到以前的版本. 我该怎么办?

想象一下在功能分支上工作. 您提取了一些更改, 创建了一些提交, 完成了您的部分功能, 并将您的更改推送到主存储库. 然后你将提交压缩成一个, 使用 git rebase -i 并再次使用 push --force. 但是发生了一些不好的事情, 你想将你的分支恢复到 rebase -i. Git 的伟大之处在于它在永不丢失数据方面做得最好, 因此之前的存储库版本 rebase 仍然可用.

在这种情况下, 您可以使用该 git reflog 命令输出存储库的详细历史记录.

对于您在本地存储库中所做的每一次 "更新", Git 都会创建一个参考日志条目. 该 git reflog 命令输出这些 reflogs, 存储在您的本地 Git 存储库中. git reflog 的输出包含更改本地存储库中分支和其他引用的提示的所有操作, 包括切换分支和 rebases. 分支的尖端 (称为 HEAD) 是对当前活动分支的符号引用. 它只是一个符号引用, 因为分支是指向提交的指针.

这是一个简单 reflog 的显示我上面描述的场景:

1b46bfc65e (HEAD -> test-branch) HEAD @ {0} : rebase -i (finish): 返回到 refs/heads/test-branch
b46bfc65e (HEAD -> test-branch) HEAD @ {1}: rebase -i ( squash): a
dd7906a87 HEAD @ {2} : rebase -i (squash): # 这是 2 个提交的组合.
a3030290a HEADC {3}: rebase -i (start): checkout refs/heads/master
Oc2d866ab HEAD@{4}: commit: c
6cab968c7 HEAD@ {5}: commit: b
a3030290a HEAD @ {6}: commit: a
c9c495792 (origin/master, origin/HEAD, master) HEAD@ {7}: checkout: 从 master 移动到 test-branch
c9c495792 (origin/master, origin/HEAD, master) HEAD@ {8} : pull: 快进

符号 HEAD@{number} 是 HEAD 在 number 更改前的位置. HEAD@{0} HEAD 现在 也是 HEAD, 四步前是 HEAD. HEAD@{4} 您可以从 reflog 上面看到 HEAD@{4}, 您需要去哪里将分支恢复到变基之前的位置, 并且 0c2d866ab 是该提交的提交 ID.

因此, 要将测试分支恢复到您想要的状态, 您需要重置分支:

$ git reset — hard HEAD@{4}

然后您可以再次强制推送以将存储库恢复到之前的位置.

一般恢复: 每当您想在您之后将分支恢复到以前的版本时 push --force, 请遵循此通用恢复解决方案模板:

  1. 使用终端获取上一次提交.
  2. 创建一个分支或重置为之前的提交.
  3. 使用 push --force.

如果您创建了一个新分支, 请不要忘记重置分支, 以便通过运行以下命令将其与远程同步:

$ git reset --hard origin/[new-branch-name]

使用 git fsck 恢复 push --force 删除的分支

假设您拥有一个存储库.

你有一个为你编写项目的开发人员.

开发人员决定删除所有分支并 push --force 提交带有消息"项目在这里"的提交.

开发商离开了该国, 无法联系或找到他们. 您没有代码, 也从未克隆过 repo.

首先, 您需要找到以前的提交.

可悲的是, 在这种情况下, 使用 git log 不会有帮助, 因为分支指向的唯一提交是"项目在这里", 没有任何相关的提交. 在这种情况下, 您必须找到没有子提交, 分支, 标记或其他引用链接到的已删除提交. 幸运的是,Git 数据库存储了这些孤儿提交, 您可以使用强大的 git fsck 命令找到它们.

git fsck --lost-found

他们称这些提交为"悬空提交". 根据文档,simplegit gc 删除了两周前的悬空提交. 在这种情况下, 您所拥有的只是悬空提交, 您剩下要做的就是找到损坏之前的前一个提交, 然后按照上面的一般恢复步骤进行操作.

受保护的分支和代码审查

正如那句老话:

"聪明人和聪明人的区别在于, 聪明人知道如何摆脱聪明人一开始就不会遇到的麻烦."

如果你想完全避免 push --force, GitHub 和 GitLab 都提供了一个非常酷的功能, 称为 Protected Branches, 它允许你将任何分支标记为受保护, 这样就没有人可以 push --force 使用它.

您还可以设置管理员首选项以限制权限.

或者, 您可以 在任何人将代码推送到重要分支之前建立 Git 挂钩以要求代码审查或批准.

本文来自:https://blog.duhbb.com

本文链接地址:我的安全使用 Git push 命令的指南,英雄不问来路,转载请注明出处,谢谢。

有话想说:那就赶紧去给我留言吧。

rainbow

这个人很懒,什么都没留下

文章评论