git使用中常见问题

本文主要解决:1、HEAD detached from问题;2、CONFLICT (modify/delete)

问题;3、git checkout uncheck问题;4、git stash问题;5、删除submodule问题

1. 游离分支(代码提交不到主分支)

在今天提交代码过程中,一直提交不上去,提示让更新再提交代码,更新之后,也报错,然后查看git 状态,报 HEAD detached from 23a38b8

查看分支,不是我常用的分支,而是游离分支,找回代码的方法:

1
2
3
git reflog 找到需要恢复的commit ,记下前面的commit id
git branch temp 23e15ab 新建一个名字叫temp的分支,用这个分支代替之前的临时分支并且拥有想要恢复的commit,23e15ab为要恢复的commit id
git checkout temp 切换到临时分支,就能找回代码

要点:git branch temp commitId,利用新分支代替之前的游离分支,并且带上游离分支最新提交记录,然后主分支合并temp分支

2. CONFLICT (modify/delete)-解决项目开发中改了相同文件同一行

在开发项目中同事改了一个公共文件,并且已经push到服务器上了,但是你也改了,并且也加了些内容

这时候当你写好代码去push的时候就会报错,如下↓

img

这时候你需要先执行:git pull

img

这里显示没有冲突的已经更新下来了,但是还是有冲突的文件,这时候打开这个文件如下↓

img

主要冲突就在红框里,你得找你同事来一起商量,这里到底该怎么合并

最后你写个最终版,然后add . => commit => push

这时候就可以了

3. git checkout --The following untracked working tree files would be overwritten

❗️ 问题分析


问题出在 Error 所列出的文件在本地的当前分支下未授权给 git 追踪,但同样命名的文件,也即出现在另一个(远程)分支下的同一文件却正在远程仓库或其它分支被 git 进行追踪,接下来的操作(git merge/checkout …)使得 git 需要呈现的是远程或另一个分支下被追踪的同名文件,但 git 并不知道该如何处理当前状态下这些未被追踪的同名文件,请求你将它们移开或删除,从而在你想要进行的操作之后直接呈现这些文件在目标状态下的版本。

✅ 解决方案


❓ 如果你想保留这些未追踪文件的变化

将这些提醒撞名的文件添加到 git 的追踪当中,并利用 stash 将这些文件的状态进行存放备份,然后执行你本来想要执行的 git 命令 overwrite 这些文件。实现:

1
2
3
1、利用 add 将这些文件进行追踪
2、git stash # 利用 stash 暂存这些文件的状态 【注:stash 将暂存当前状态下所有未 push 的改变】
3、 执行你本来想要执行的命令 (git pull/merge/checkout ...)

❓ 这些文件已经过时或纯属冗余,别 bb,我就想 overwrite

那很简单,选择一切带有 -f 的操作,谨慎使用简单恐怖的 clean 命令。实现举例:

1
git checkout -f target-branch  # override 未追踪但撞名的文件

4. git stash

❗️ 问题分析


紧急切换分支时,当前分支feature还没有做完不想提交,切换分支时必须保留当前分支未完成的代码。

假如我现在的代码是这样的:

1
2
3
4
5
public static void main(String[] args) {
System.out.println("我是 feature 分支原有的代码");
// ...
System.out.println("我是正在开发的代码");
}

接着上面的情景,我需要把正在开发的代码给藏起来,那么直接使用 git stash 命令即可,使用后就会变成这样的效果:

1
2
3
4
public static void main(String[] args) {
System.out.println(我是 feature 分支原有的代码");
// ...
}

✅ 解决方案


好了,正在 feature 分支还没写完的代码已经被藏起来了,此时,好奇心满满的你想着,它是被藏到哪里去呢?一顿谷歌之后,你发现可以通过这个命令查看 git stash list,如图:

img

图中的 stash@(0) 就是被藏起来的记录了,知道真相的你这下可以放心地去处理线上问题了。

你很牛皮,线上问题没一会功夫就搞定了,此时你再次切回刚才的 feature 分支,想要把刚才藏起来的代码拿出来。好了,一顿谷歌之后,你发现有两种拿的方法,分别是:

1、git stash pop

2、git stash apply

那这两者有什么不同呢?还记得刚才提交到 git stash list 命令显示的结果吗?—— stash@(0)

git stash pop 的是恢复刚才被藏起来的代码,同时删除 stash@(0) 这条记录也删了,此时你再使用 git stash list 命令就没有结果了:

img

明白 git stash pop 的作用后,那 git stash apply 命令也很好理解了,它们唯一的不同就是 git stash apply 命令不会删除stash@(0) 这条记录。

最后,如果你在一个分支上使用了 n 次 git stash 命令,那么就会有 stash@(0)、stash@(1)、…、stash@(n),对应一共有 n 条记录。

那我们要这么多条记录有什么用呢?

答案就是我们可以指定 git stash pop/apply 哪条记录。假如我想要恢复 stash@(1) 记录。那么对应的命令是 git stash pop stash@(1) 或 git stash apply stash@(1)

5. 5步删除git submodule

1. 删除submodule缓存

需要先暂存 .gitmodules 文件, 否则会报错: fatal: please stage your changes to .gitmodules or stash them to proceed

1
2
git add .gitmodules
git rm --cached submodule_name

2. 删除submodule目录

1
rm -rf submodule_name

3. 修改.gitmodules

移除对应的submodule信息, 只有1个submodule信息也可以删除该文件.
image.png

4. .git/modules

移除对应的submodule目录
image.png

5. .git/config

移除对应的submodule信息
image.png

5、删除submodule

网上流传了一些偏法,主要步骤是直接移除模块,并手动修改 .gitmodules.git/config.git/modules 内容。包含了一大堆类似git rm --cached <sub-module>rm -rf <sub-moduel>rm .gitmodulesgit rm --cached 之类的代码。

实际上这是一种比较野的做法,不建议使用。

根据官方文档的说明,应该使用 git submodule deinit 命令卸载一个子模块。这个命令如果添加上参数 --force,则子模块工作区内即使有本地的修改,也会被移除。

git submodule deinit project-sub-1
git rm project-sub-1

执行 git submodule deinit project-sub-1 命令的实际效果,是自动在 .git/config 中删除了以下内容:

[submodule “project-sub-1”]
url = https://github.com/username/project-sub-1.git

执行 git rm project-sub-1 的效果,是移除了 project-sub-1 文件夹,并自动在 .gitmodules 中删除了以下内容:

[submodule “project-sub-1”]
path = project-sub-1
url = https://github.com/username/project-sub-1.git

此时,主项目中关于子模块的信息基本已经删除(虽然貌似 .git/modules 目录下还有残余):

➜ project-main git:(master) ✗ gs
位于分支 master
您的分支与上游分支 ‘origin/master’ 一致。
要提交的变更:
(使用 “git reset HEAD <文件>…” 以取消暂存)
修改: .gitmodules
删除: project-sub-1

可以提交代码:

git commit -m “delete submodule project-sub-1”

至此完成对子模块的删除。