前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Git那些事系列:从业务场景到高级技巧的完整指南(三)

Git那些事系列:从业务场景到高级技巧的完整指南(三)

作者头像
粲然忧生
修改2023-10-16 21:06:32
1810
修改2023-10-16 21:06:32
举报
文章被收录于专栏:工程师的分享

文件修改的记录居然没有了!!!

如何隐蔽的把一次修改记录搞丢!

大家好,有到了Git那些事系列了,近期笔者遇到了一个十分奇怪的事情,一个Git仓库的文件被莫名其妙的修改了,问题是,一点修改记录都没有!!!经过仔细的溯源,终于发现原来Git对文件的记录也不是万能,这里做个沉淀,供大家参考

配置文件被异常修改了

在一个岁月静好的一天,笔者使用一个开发分支测试环境做编包和部署,发布的时候突然报错,查看原因是某个配置文件异常,一些部署相关代码被删除了! 当然,这件事情看起来很离谱 但在多人频繁开发的项目团队 也很正常!

那就查查到底哪次提交修改了?

,顺便问问修改的同学,删除的背景是啥 然后! 居然没有找到该配置代码修改记录!!! 只找到两次该文件异常的修改记录

如上如所示,在下面红框这里,需要的配置代码还在,但在上面红框里面,配置代码已经没有了 同时,除了这两个红框的提交,中间的提交并没有对该配置代码所在的配置文件进行修改 然而,在上面的红框里面,没有该配置代码的修改变更记录

也就是说,这个文件的部分代码的变更

在某次提交的后,该文件的部分代码突然被删了,且修改记录没这部分代码

**

难道是Git的BUG?

到底什么时候会导致Git记录丢失呢?

第一种可能:文件删除后又重新进行添加

因为Git对文件的跟踪是连续的,当删除之后再次添加就会导致Git对该文件的跟踪失效,在这里的场景下,虽然,该文件的部分代码丢失没有记录,但该文件的另一部分修改被记录了(下图),所以,Git对整个文件的跟踪并没有丢失,所以并不是一个删除后又添加的场景

第二种可能:本地的修改未及时提交,导致被覆盖

这里就是本地的多次修改没有逐项提交,或者完整提交,导致中间部分修改没有修改记录,但在这里中间的修改记录指的是本地的修改记录。对于远端的提交记录来说,它们是连续的。所以也不是这种情况

第三种可能:Git reset强制修改

这是一个相对常用的一个命令, git reset [--soft | --mixed | --hard] [HEAD] 简单做下介绍:

git reset HEAD^ # 回退所有内容到上一个版本 git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本 git reset 052e # 回退到指定版本

这里比较有意思的是三个参数: hard:重置位置的同时,直接将 working Tree工作目录、 index 暂存区及 repository 都重置成目标Reset节点的內容,所以效果看起来等同于清空暂存区和工作区。 soft:重置位置的同时,保留working Tree工作目录和index暂存区的内容,只让repository中的内容和 reset 目标节点保持一致,因此原节点和reset节点之间的【差异变更集】会放入index暂存区中(Staged files)。所以效果看起来就是工作目录的内容不变,暂存区原有的内容也不变,只是原节点和Reset节点之间的所有差异都会放到暂存区中。 mixed:(默认)重置位置的同时,只保留Working Tree工作目录的內容,但会将 Index暂存区 和 Repository 中的內容更改和reset目标节点一致,因此原节点和Reset节点之间的【差异变更集】会放入Working Tree工作目录中。所以效果看起来就是原节点和Reset节点之间的所有差异都会放到工作目录中。 如图所示:

这篇文章写的比较好:Git Reset 三种模式

使用场景:

hard:1.要放弃目前本地的所有改变時 2.真的想抛弃目标节点后的所有commit soft:想合并「当前节点」与「reset目标节点」之间不具太大意义的 commit 记录(比如解一个BUG的前前后后的提交,这里如果分支合并的场景用checkout – path效果一样) mixed:(默认)那些提交还想好好看看,留一些,删一些,改一些,总之就是不确定的情况

**

当然,这个场景并不是无痕的,可以通过git reflog来查看Head或者分支的变化

下面是一个示例:

假设你的 Git 仓库有以下提交历史:

代码语言:javascript
复制
commit 1234567 (HEAD -> master)
Author: John Doe <johndoe@example.com>
Date:   Mon Jul 26 14:00:00 2021 -0500

    Add new feature

commit abcdefg
Author: John Doe <johndoe@example.com>
Date:   Fri Jul 23 10:00:00 2021 -0500

    Update README.md

commit 9876543
Author: John Doe <johndoe@example.com>
Date:   Wed Jul 21 16:00:00 2021 -0500

    Initial commit

现在你想回退到上一个提交,使用以下命令:

代码语言:javascript
复制
$ git reset HEAD~1

现在你的提交历史变成了这样:

代码语言:javascript
复制
commit abcdefg (HEAD -> master)
Author: John Doe <johndoe@example.com>
Date:   Fri Jul 23 10:00:00 2021 -0500

    Update README.md

commit 9876543
Author: John Doe <johndoe@example.com>
Date:   Wed Jul 21 16:00:00 2021 -0500

    Initial commit

然后你可以使用 git reflog 命令查看提交历史的变化:

代码语言:javascript
复制
$ git reflog
1234567 HEAD@{0}: reset: moving to HEAD~1
abcdefg HEAD@{1}: commit: Update README.md
9876543 HEAD@{2}: commit (initial): Initial commit

在这个示例中,git reflog 显示了 HEAD@{0},它是你最近的操作,即使用 git reset 回退到上一个提交。 HEAD@{1} 是回退之前的提交,即 abcdefg。

回到问题本身在笔者遇到的这个场景下,并没有发现异常的Git reset的操作

git reset HEAD是用来重置暂存区和工作区的,并没有重置HEAD

第四种可能:force push强制修改

git push --force origin master 这个也是一个偶尔会用到的命令,一般用来填坑,就是把本地的强制覆盖到远端,而远端的一些修改记录(本地没有的修改记录)就没有了,这样也会导致某个文件的修改记录不完善

当然,这个场景也不是无痕的,可以通过git reflog来查看

例如,假设你在本地仓库中执行了以下操作:

代码语言:javascript
复制
$ git add main.js
$ git commit -m "Add new feature"
$ git push --force

然后,你执行了 git reflog 命令,可以看到类似以下的输出:

代码语言:javascript
复制
$ git reflog
7b1c3f9 (HEAD -> master) HEAD@{0}: push: forced-update
a3b2e8d HEAD@{1}: commit: Add new feature

回到这个问题,根据上一章的截图,也没有看到push --force的操作

第五种可能:Merge的脏提交

代码合并是一个老生常谈的点,也是绝大部分出现问题的根因

代码语言:javascript
复制
git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
    [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
    [--[no-]allow-unrelated-histories]
    [--[no-]rerere-autoupdate] [-m <msg>] [<commit>…​]
git merge --abort
git merge --continue

这里的-s,和-X都是一个策略,具体可以参考:Git 合并策略选项和示例

同时,由于Merge中,可能会有冲突,这就导致在这个中间状态如果增加了一部分额外的修改,并不会被记录进来,而且如果额外的修改就在这个冲突的文件里面的话,确实可能会出现,文件有修改记录,但额外代码没有修改记录

针对这次问题,会不会是这个原因呢?

首先,git的操作是比较复杂的,仅仅是看git log是看不出来的。如果要查看这种无记录的修改,得分析下每次push产生的最新版本里,文件是否已经被改坏,从而查到是哪次push有问题

git show abc123:xxx.go

这里的push比较多,而且是多分支的,所以排查起来会比较慢

这里有两种情况 1.某次合并时,两个父节点,一个父节点对问题代码有删除,一个父节点对问题代码没有删除

这种一般是正常的合并

2.某次合并时,两个父节点,两个父节点对问题代码都没有修改,但合并后却删除了,那问题就在这里了

经过笔者多分支一次一次push的回溯,终于找到了这个疑似的合并 本地复现一下: git checkout 93f13bqqa1 && git merge 8f9c013f8e

发现该文件确实需要解冲突,但丢失的代码其实不在解决冲突的范围内

那在解冲突的时候,顺手把丢失的代码删除下,是不是就没有记录了?

解完冲突后,git add和git commit之后,发现删除的diff确实没有了:

看来是合并的时候,解决冲突的时候误删了一些代码 好吧

问题解决

这里给出的经验: 1.合并是一个容易出问题的地方 2.合并的冲突解决是一个容易出问题的地方 3.避免冲突的方案是分支快拉快合,避免分支长时间不合入(一周以上) 4.每次合并不要进行大量代码修改,每次拉分支只做一件事 5.每一次记录的修改都能找到问题的点,只是比较麻烦。。。。

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-09-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何隐蔽的把一次修改记录搞丢!
    • 配置文件被异常修改了
      • 那就查查到底哪次提交修改了?
        • 在某次提交的后,该文件的部分代码突然被删了,且修改记录没这部分代码
          • 到底什么时候会导致Git记录丢失呢?
            • 第一种可能:文件删除后又重新进行添加
              • 第二种可能:本地的修改未及时提交,导致被覆盖
                • 第三种可能:Git reset强制修改
                  • 使用场景:
                • 第四种可能:force push强制修改
                  • 第五种可能:Merge的脏提交
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档