一次惊险的git操作

前两天写完一篇文章,但是还没有发布,因为一直在调试hexo和next-theme的配置。然后就发生了一件很悲催的事情,执行了git add .,正准备git commit时,发现有很多文件不想加到git仓库,也就是在工作区执行了add,但是还没有commit,此时脑袋一热,执行了git reset --hard HEAD,然后就悲剧了,工作区的修改全没了。

脑袋嗡的一下,敲完回车的那一刹那我就感觉哪里不对了,但为时已晚。

先说一下如果想恢复缓存区里工作区的修改,其实很简单,git status的提示也很清楚:

❯ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   _config.next.yml
        modified:   _config.yml
        new file:   source/_posts/一次危险的git操作.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   source/_posts/一次危险的git操作.md

注意,这里我已经在git add后又修改了一次危险的git操作.md这个文件,这里的修改当然包括删除操作。

此时只需要git restore .,就可以把工作区恢复到上次add时的状态,即取消当前工作区的修改。

而如果加上--staged参数,则把缓存区的内容恢复到工作区,注意此时工作区的修改不会被取消,即如果工作区删除了文件,那执行git restore --staged是无法恢复的。

要是git add .后删除了文件,然后又执行了git reset --hard HEAD,那就无法简单恢复了。

如何能恢复呢?

我在网上一通搜索,某乎上这个帖子还是提供了很好的参考,但不是很详细。

大致上的解决方法有两个:git refloggit fsck --lost-found

  1. git reflog
❯ git reflog
ffe9822 (HEAD -> main) HEAD@{0}: reset: moving to HEAD
ffe9822 (HEAD -> main) HEAD@{1}: reset: moving to HEAD
ffe9822 (HEAD -> main) HEAD@{2}: commit: mofify: 修改配置文件
a8de715 (origin/main) HEAD@{3}: commit: add: 添加文章
e3bb4d8 HEAD@{4}: reset: moving to HEAD
e3bb4d8 HEAD@{5}: commit: modify _config
d7e58c5 HEAD@{6}: Branch: renamed refs/heads/master to refs/heads/main
d7e58c5 HEAD@{8}: commit (initial): init commit

这个命令,我的理解可以解决丢步的情况,比如reset到了更早的commit,把那之后的commit给整没了,此时可以用这个命令恢复。

  1. git fsck --lost-found
❯ git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling tree 051912e095bb9d741aeec78c41afc051c6bb98db
dangling blob 8ef0c755cba8a88e113c90f378902f0b7914c32c
dangling blob 3cd9b74819ac88752c9e1a6b3c95b71e0860cdb0
dangling blob dcc06571a9d69efea1046f3f7d2b7e9303aa5509
dangling blob ee5beaf30617b77b02db09b71d7eca0039c8f76c
dangling blob f857e88e2aed2cf87dc877ebe3c29b53fd21aaad

看到这个,问题基本就解决了。接下来就是把对应文件进行恢复。

❯ git show 8ef0c755cba8a88e113c90f378902f0b7914c32c
---
title: 一次危险的git操作
date: 2022-11-15 14:03:34
tags:
    - git
---

前两天写完一篇文章,但是还没有发布,因为一直在调试hexo和next-theme的配置。然后就发生了一件很悲催的事情,执行了`git add .`,正准备`git commit`时,发现有很多文件不想加到git仓库,也就是在工作区执行了add,但是还没有commit,此时脑袋一热,执行了`---
title: 一次危险的git操作
date: 2022-11-15 14:03:34
tags:
    - git
---

前两天写完一篇文章,但是还没有发布,因为一直在调试hexo和next-theme的配置。然后就发生了一件很悲催的事情,执行了`git add .`,正准备`git commit`时,发现有很多文件不想加到git仓库,也就是在工作区执行了add,但是还没有commit,此时脑袋一热,执行了`git reset --hard HEAD`,然后就悲剧了,工作区的修改全没了。

脑袋嗡的一下,敲完回车的那一刹那我就感觉哪里不对了,但为时已晚。

先说一下如果想恢复缓存区里工作区的修改,其实很简单,`git status`的提示也很清楚:

```powershell
❯ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   _config.next.yml
        modified:   _config.yml
        new file:   source/_posts/一次危险的git操作.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
:

不同的文件对应不同的文件和状态,找到自己需要的状态恢复即可。

我当时用这个命令并没有起作用,转而使用的另一个方法。git的所有操作都是增量操作,除非特别刻意地去删除,否则要想让一个文件消失得无影无踪还是有点儿困难的。这个方法是直接去.git/objects目录查找。参考了这篇文章

如果用git bash的话可以使用find命令进行查找:find .git/objects -type f | xargs ls -lt | sed 30q,这条命令输出最近add的30个文件,可以根据情况设置相应的值。Windows中没有find命令,需要在git bash中执行

我使用的是powershell,用fd命令替代find

❯ fd . '.\.git\objects' -t f --changed-within '2022-11-15'
.git\objects\09\2c9306cd5b2761048b8020a0802a6a4a068ed7
.git\objects\3c\d9b74819ac88752c9e1a6b3c95b71e0860cdb0
.git\objects\6a\36a8a9c4b02c92684bc67ed65cdd12ee055de3
.git\objects\8a\c69f0b1d0032ace1e6e18f70d2bfc103591560
.git\objects\8e\f0c755cba8a88e113c90f378902f0b7914c32c
.git\objects\a0\37eb5a4333bdcc625f9ea4e5df13b0487e470b
.git\objects\b8\36d4b7235fe833fee00ea9278082d5ba4354f7
.git\objects\dc\c06571a9d69efea1046f3f7d2b7e9303aa5509
.git\objects\ee\5beaf30617b77b02db09b71d7eca0039c8f76c
.git\objects\f8\57e88e2aed2cf87dc877ebe3c29b53fd21aaad
.git\objects\ff\e9822967eac8c6e6845fbc133b18a13d11d446

从这里可以看出结果跟上面的git fsck --lost-found是基本一致的。这个方法需要把结果处理下:.git\objects\09\2c9306cd5b2761048b8020a0802a6a4a068ed7 → 092c9306cd5b2761048b8020a0802a6a4a068ed7,可以使用脚本,也可以重定向到文件然后用编辑器批量修改的方法,然后再用git show就可以了。

如果文件比较多的话,可以编写脚本

$f = Get-Content .\files.txt  # 假定上一步将结果重定向到files.txt,并且已经批量编辑为需要的格式
foreach ($l in $f){git show $l | out-file x$l.txt}

这里用powershell有一个大坑,就是如果文件中有中文的话,得到的文本文件会有乱码。用git bash和cmd则没有这个问题。问题是很容易绕过去解决,但是不找到原因怎么睡得着?因为git show的输出是没有问题的,所以想来想去,觉得问题应该就是出在powershell的默认编码上,后来一通搜索,在github这个issue得到了确认。

[console]::inputencoding;[console]::outputencoding

EncodingName      : Chinese Simplified (GB2312)
WebName           : gb2312
HeaderName        : gb2312
BodyName          : gb2312
Preamble          :
WindowsCodePage   :
IsBrowserDisplay  :
IsBrowserSave     :
IsMailNewsDisplay :
IsMailNewsSave    :
IsSingleByte      : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : True
CodePage          : 936

EncodingName      : Chinese Simplified (GB2312)
WebName           : gb2312
HeaderName        : gb2312
BodyName          : gb2312
Preamble          :
WindowsCodePage   :
IsBrowserDisplay  :
IsBrowserSave     :
IsMailNewsDisplay :
IsMailNewsSave    :
IsSingleByte      : False
EncoderFallback   : System.Text.InternalEncoderBestFitFallback
DecoderFallback   : System.Text.InternalDecoderBestFitFallback
IsReadOnly        : False
CodePage          : 936

对,问题就出在这,应该跟安装powershell时系统语言有关系。要解决这个问题,建议还是不要修改默认配置,只修改当前控制台的变量就好(只在当前终端生效)。

[console]::inputencoding = [console]::outputencoding = [System.Text.Encoding]::UTF8
❯ [console]::inputencoding;[console]::outputencoding

Preamble          :
BodyName          : utf-8
EncodingName      : Unicode (UTF-8)
HeaderName        : utf-8
WebName           : utf-8
WindowsCodePage   : 1200
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.EncoderReplacementFallback
DecoderFallback   : System.Text.DecoderReplacementFallback
IsReadOnly        : False
CodePage          : 65001

Preamble          :
BodyName          : utf-8
EncodingName      : Unicode (UTF-8)
HeaderName        : utf-8
WebName           : utf-8
WindowsCodePage   : 1200
IsBrowserDisplay  : True
IsBrowserSave     : True
IsMailNewsDisplay : True
IsMailNewsSave    : True
IsSingleByte      : False
EncoderFallback   : System.Text.EncoderReplacementFallback
DecoderFallback   : System.Text.DecoderReplacementFallback
IsReadOnly        : False
CodePage          : 65001

这时再执行前面的脚本,输出应该就正常了。如果文件不多,直接复制一份出来直接对照文件内容改回原来的文件名也行。

总结

  1. git仓库中还是不要做shift+del这种操作
  2. git reset --hard要谨慎
  3. 遇到问题别慌,耐心找方法
  4. git的3个区还是要加深理解
  5. 学无止境

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。

<think>好的,我现在需要帮助用户了解首次使用Git时的基本操作步骤。首先,用户可能是一个刚开始接触Git的新手,所以需要从最基础的安装和配置开始。根据引用[^1]提到的Git Community Book和Pro Git等资源,这些都是权威的参考资料,可以用来确保步骤的正确性。 第一步应该是安装Git。用户可能使用的是不同的操作系统,所以需要分别说明Windows、macOS和Linux的安装方法。比如,在Windows上推荐下载Git for Windows,而macOS可以使用Homebrew,Linux则用包管理器安装。这部分需要简明扼要,避免让用户感到困惑。 接下来是配置用户信息,这是使用Git前必须的步骤,包括设置用户名和邮箱。这里要提醒用户使用和GitHub或其他平台相同的邮箱,方便后续协作。同时,可能需要解释这些信息的作用,比如在提交时标识身份。 然后是初始化仓库,用户需要知道如何将现有项目转换为Git仓库或者克隆远程仓库。这里要区分git init和git clone的区别,并给出具体的命令示例。例如,克隆一个远程仓库可能更常见,尤其是从GitHub上获取代码。 基础操作部分应包括添加文件、提交更改、查看状态和查看提交历史。这些是日常使用中最频繁的命令,需要详细说明每个步骤的作用。比如,git add . 是添加所有更改,而git commit -m "message"则是提交到本地仓库。同时,git status和git log可以帮助用户了解当前状态和历史记录。 连接到远程仓库也是关键步骤,特别是推送到GitHub等平台。需要解释git remote add origin的作用,以及git push的用法。可能还需要提到第一次推送时可能需要验证身份,比如使用SSH密钥或者HTTPS密码。 最后,生成相关问题需要考虑用户可能遇到的后续问题,比如如何处理冲突,分支管理,或者忽略文件。这些问题可以引导用户进一步学习Git的高级功能。 检查所有步骤是否符合系统级指令,比如行内数学表达式是否正确使用$...$格式,虽然这里可能用不到数学公式,但其他格式如代码块是否正确使用三个反引号,引用是否在段落末尾自然添加。例如,在提到Git Community Book的时候加上。 还需要确保回答结构清晰,分步骤说明,每个步骤都有对应的命令和解释。同时,引用的资料要准确,确保用户可以根据这些参考资料深入学习。 现在,整理这些思路,按照用户的要求分步骤写出首次使用Git的基本操作,并在适当的位置添加引用。最后生成相关问题,帮助用户进一步探索Git的使用。</think>### 首次使用Git的基本操作步骤 #### 1. 安装Git - **Windows**: 下载 [Git for Windows](https://git-scm.com/download/win) 并安装,安装时保持默认选项。 - **macOS**: 使用 `brew install git`(需提前安装 [Homebrew](https://brew.sh/))。 - **Linux**: 使用包管理器安装,例如 Ubuntu/Debian: `sudo apt install git`。 #### 2. 配置用户信息 打开终端(或Git Bash),设置全局用户名和邮箱: ```bash git config --global user.name "你的名字" git config --global user.email "你的邮箱@example.com" ``` *注:此信息会关联到所有提交记录,建议与GitHub等平台注册邮箱一致。* #### 3. 初始化仓库 - **新建仓库**:进入项目目录后执行: ```bash git init # 将当前目录初始化为Git仓库 ``` - **克隆远程仓库**: ```bash git clone https://github.com/用户名/仓库名.git # 克隆远程仓库到本地 ``` #### 4. 基础操作流程 - **添加文件到暂存区**: ```bash git add 文件名 # 添加单个文件 git add . # 添加所有修改和新文件 ``` - **提交更改到本地仓库**: ```bash git commit -m "提交说明" # 提交暂存区的修改 ``` - **查看状态**: ```bash git status # 显示工作目录和暂存区的状态 ``` - **查看提交历史**: ```bash git log # 显示提交记录(按Q退出) ``` #### 5. 连接到远程仓库(以GitHub为例) - **关联远程仓库**: ```bash git remote add origin https://github.com/用户名/仓库名.git ``` - **推送本地代码**: ```bash git push -u origin main # 首次推送需指定分支(main/master) ``` ### 示意图:Git基础工作流 ``` 工作目录 → `git add` → 暂存区 → `git commit` → 本地仓库 → `git push` → 远程仓库 ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值