引子

在撰写有关 Git 的文章时,我注意到很多人都对 Git 的错误消息感到困惑。我已经花了很多年才习惯这些错误消息,所以我花了很长时间才明白为什么人们会感到困惑,但经过更多的思考,我意识到:

1. 有时我确实会被错误信息搞糊涂,我只是习惯了困惑
2. 当git给出的错误消息不够有用时,我有很多方法来获取更多信息

因此在这篇文章中,我将介绍 Git 的一系列错误消息,列出我认为每个错误消息中令人困惑的一些地方,并讨论当我对这些消息感到困惑时我会做什么。

改进错误信息并不容易

在开始之前,我想说的是,尝试思考这些错误消息为什么令人困惑让我非常敬佩维护 Git 在这里插入代码片的难度。几个月来我一直在思考 Git,对于其中一些消息,我真的不知道如何改进它们。

在我看来,改进错误信息有些困难:

1. 如果你想出一个新消息的想法,很难说它是否真的更好!
2. 改进错误信息等工作通常得不到资助
3. 错误信息必须翻译(git 的错误信息被翻译成19 种语言!工作量可想而知)

话虽如此,如果您发现这些信息令人困惑,希望其中一些注释能够帮助您稍微澄清一下。

error: git push on a diverged branch

$ git push
To github.com:jvns/int-exposed
! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'github.com:jvns/int-exposed'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

$ git status
On branch main
Your branch and 'origin/main' have diverged,
and have 2 and 1 different commits each, respectively.

我发现有些事情令人困惑:

1. 无论是后面的分支还是分支分叉,你都会收到完全相同的错误消息。无法从此消息中判断是哪种情况:你需要运行git status或git pull找出原因。

2.它说failed to push some refs,但并不完全清楚它未能推送哪些引用。我相信未能推送的所有内容都会以 ! [rejected]在上一行中——展现, 就像本例子里面的main分支。

如果我感到困惑,我喜欢做什么:

1. 我会运行git status以弄清楚我当前分支的状态。

2. 我想我几乎从来没有尝试过一次推送多个分支,所以我通常完全忽略 git 关于哪个特定分支推送失败的注释——我只是假设它是我当前的分支

error: git pull on a diverged branch

$ git pull
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches

我认为这里最让人困惑的是 git 为你提供了大量的选项:它说你可以:

1. 本地配置pull.rebase false、pull.rebase true或pull.ff only
2. 或者全局配置上面三个参数
3. 或者运行git pull --rebase或者git pull --no-rebase

很难想象 git 初学者如何能轻松地使用这个提示来自己弄清楚所有这些选项。

如果我向朋友解释这一点,我会这样说,“你可以使用git pull --rebase 或执行 git pull --no-rebase通过rebase或merge来解决这个问题 ,如果你想设置永久生效的参数,可以使用git config pull.rebase false 或者 git config pull.rebase true

git config pull.ff only对我来说感觉有点多余,因为这个参数是 git 的默认行为(尽管并非总是如此)。

我喜欢在这样做事情:

1. 运行git status以查看当前分支的状态
2. 也许运行git log origin/main或者git log看看分歧的提交是什么
3. 通常运行git pull --rebase来解决它
4. 有时我会运行git push --force,或者git reset --hard origin/main 如果我想丢弃我的本地工作或远程工作(例如因为我不小心提交到了错误的分支,或者因为我git commit --amend在只有我正在使用的个人分支上运行并且想要强制推送)

error: git checkout asdf (a branch that doesn’t exist)

$ git checkout asdf
error: pathspec 'asdf' did not match any file(s) known to git

这有点奇怪,因为我们的目的是检查一个分支,但却 git checkout提示不存在的路径。

发生这种情况是因为git checkout的第一个参数可以是分支或路径,而 git 无法知道你是要的哪一个。这似乎很难改进,但我可能希望出现类似“没有这样的分支、提交或路径:asdf”的情况。

我喜欢这样做:

1. 理论上来说,用git switch替代会更好,但是git checkout我还是继续用
2. 通常我只记得我需要将其理解为“分支asdf不存在”

error: git switch asdf (a branch that doesn’t exist)

$ git switch asdf
fatal: invalid reference: asdf

git switch只接受分支作为参数(除非你传递-d),那么为什么它会说invalid reference: asdf而不是invalid branch: asdf?这点没搞懂。

我认为原因在于,它在内部git switch试图通过错误消息提供帮助:如果你运行git switch v0.1切换到标签,它会说:

$ git switch v0.1
fatal: a branch is expected, got tag 'v0.1'`

因此,git 试图传达的信息fatal: invalid reference: asdf是“asdf不是分支,也不是标签,也不是任何其他引用”。从我进行的各种git 调查来看,我的印象是,很多 git 用户根本不知道 git 中的“引用”是什么,所以我不确定这是否传达了信息。

我喜欢这样做:

90% 的时间当出现 git 错误消息提示:reference我只是在脑海中将其替换为branch。

error: git checkout HEAD^

$ git checkout HEAD^
Note: switching to 'HEAD^'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c 

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 182cd3f add "swap byte order" button

这是一个棘手的问题。肯定有很多人对这条消息感到困惑,但显然也有很多人努力来改进它。关于这一点,我没有什么好说的。

我喜欢这样做:

1. 我的 shell 提示会告诉我是否处于分离的 HEAD 状态,并且通常我可以记住不能在该状态下进行新的提交

3. 当我查看完我想要查看的旧提交后,我会运行git checkout main或执行其他操作返回分支

message: git status when a rebase is in progress

这不是一个错误消息,但我仍然发现它本身有点令人困惑:

$ git status
interactive rebase in progress; onto c694cf8
Last command done (1 command done):
   pick 0a9964d wip
No commands remaining.
You are currently rebasing branch 'main' on 'c694cf8'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged ..." to unstage)
  (use "git add ..." to mark resolution)
  both modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

我认为这里做两个事情可以更清晰:

1 我认为 You are currently rebasing branch 'main' on 'c694cf8' 如果在第一行而不是第五行会更好.—现在第一行没有说你要重新定基哪个分支。

2 在这种情况下,c694cf8实际上是origin/main,所以我觉得提示 You are currently rebasing branch 'main' on 'origin/main'可能更清楚。

我喜欢这样做:

我的 shell 提示符包含我当前正在重新定基的分支,因此我依赖它而不是 的输出git status。

error: git rebase when a file has been deleted

$ git rebase main
CONFLICT (modify/delete): index.html deleted in 0ce151e (wip) and modified in HEAD.  Version HEAD of index.html left in tree.
error: could not apply 0ce151e... wip

我仍然对此感到困惑的是: –index.html在 HEAD 中被修改了。但是 是什么HEAD?它是我在开始合并/变基时正在处理的提交,还是来自其他分支的提交?(答案是“HEAD如果您正在进行合并,则是您的分支;如果您正在进行变基,则是“其他分支”,但我总是觉得很难记住)

我认为如果消息尽可能列出分支名称,我个人会更容易理解,如下所示:

CONFLICT (modify/delete): index.html deleted on `main` and modified on `mybranch`

error: git status during a merge or rebase (who is “them”?)

$ git status 
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)
Unmerged paths:
(use “git add/rm …” as appropriate to mark resolution)
deleted by them: the_file

no changes added to commit (use “git add” and/or “git commit -a”)

我发现这个与上一个消息完全一样令人困惑:它说deleted by them:,但是“them”指的是取决于你是否进行了merge或rebase或 cherry-pick。

1 对于merge,them您合并的另一个分支是
2 对于rebase,them是你运行时所在的分支git rebase
3 对于cherry-pick,我猜这是你挑选的提交

如果我感到困惑,我喜欢做什么:

1 试着回忆一下我做了什么
2 如果我记不清了,可以运行git show main --stat 或用其他方法查看我在main分支上做了什么

error: git clean

$ git clean
fatal: clean.requireForce defaults to true and neither -i, -n, nor -f given; refusing to clean

我只是觉得有点困惑,你需要查找-i、-n和 -f才能理解这个错误信息。我个人太懒了,所以即使我可能已经使用了git clean10 年,我仍然不知道-i( ) 代表什么interactive,直到我写下这个。

如果我感到困惑,我喜欢这样做:

通常我只是匆忙地执行git clean -f删除所有未跟踪的文件并希望得到最好的结果,尽管git clean -i 现在我知道了它的含义,我可能会改用-i它。看起来安全多了。

就这样!

希望这些能够对你有帮助!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐