为什么我推送后远程Git仓库中有未提交的更改?

3

我使用以下命令设置了一个新的Git存储库:

mkdir plans-for-world-domination
cd plans-for-world-domination
git init
echo "MWA HA HA HA HA!" > plans.txt
git add .
git commit -m "Beginning my plans..."

我先克隆了这个代码库,做出了一些更改,提交了更改后,尝试进行推送:

cd ..
git clone plans-for-world-domination clone
cd clone
echo "Step 1: set up super secret spy base in Cleveland, Ohio" >> plans.txt
git commit -am "Update plans"
git push origin master

但是当我再次进入plans-for-world-domination存储库时,暂存区/索引中已经暂存了与我刚刚推送的更改相反的更改:

$ cd ../plans-for-world-domination
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   plans.txt

$ git diff --staged
diff --git a/plans.txt b/plans.txt
index febb495..ce01362 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,2 +1 @@
 MWA HA HA HA HA!
-Step 1: set up super secret spy base in Cleveland, Ohio

为什么我的第一个仓库有这些未暂存的更改,这些更改与我刚推送的相反,我该如何解决?

相关:Git配置receive.denyCurrentBranch - user456814
1个回答

8

在非裸仓库中,推送不会更新工作副本和暂存区

由于第一个仓库是非裸仓库,即包含工作副本(也经常在 Git 文档中称为工作目录树),因此看起来暂存区包含了刚刚推送的更改的反向变化。而仓库则没有工作副本目录。

由于该仓库是非裸的,因此当您对其进行推送时,推送只会更新分支引用和符号HEAD引用,因为git push不会操作存在于非裸仓库中的工作副本和暂存区。

因此,非裸仓库的工作副本和暂存区仍然停留在更新HEAD之前存在的仓库状态上。换句话说,工作副本和暂存区的实际状态与指向的提交状态不匹配。这就是为什么运行git statusgit diff时会显示这两种状态之间的差异的原因:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   plans.txt

$ git diff --staged
diff --git a/plans.txt b/plans.txt
index febb495..ce01362 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,2 +1 @@
 MWA HA HA HA HA!
-Step 1: set up super secret spy base in Cleveland, Ohio

(次优)解决方案:硬重置

由于工作副本和暂存区与 HEAD 不同步,将它们重新匹配的一种解决方案是简单地使用

git reset --hard HEAD
git reset --hard

重置工作区和暂存区到由HEAD指向的提交。

然而,这并不是理想的解决方案...

理想解决方案:推送到裸仓库

你并不应该推送到非裸仓库,因为它们的工作区和暂存区可能会与仓库引用不同步。相反,除非你有一个不寻常的原因要推送到非裸仓库,否则你真的应该推送到裸仓库,因为它们没有工作副本。

要创建一个裸仓库,只需使用--bare标志:

# Initialize a bare repo
mkdir bare
cd bare
git init --bare

# Push changes to the bare repo
cd ..
mkdir project
cd project
# Make some changes and commit
git remote add origin ../bare
git push origin master

# Or create a bare clone from another bare or non-bare repo
git clone --bare <repo-path-or-uri>

从Git 1.6.2版本开始,默认禁止向非裸仓库推送

请注意,自Git版本1.6.2起,默认情况下禁止向非裸仓库推送:

在下一个主要版本中,默认情况下将拒绝推送到当前检出的分支中。您可以通过设置接收存储库中的配置变量receive.denyCurrentBranch来选择此类推送的执行操作。

事实上,当您尝试使用当前版本的Git向非裸仓库推送时,应该会拒绝您的推送,并显示以下错误消息(略微修改以缩短长度):

$ git push origin master
Total 0 (delta 0), reused 0 (delta 0)
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
error:
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.
error:
error: To squelch this message and still keep the default behaviour, set
error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To non-bare
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'non-bare'

正如上面的错误消息所解释的那样,您可以通过禁用远程非裸库中的receive.denyCurrentBranch配置设置来禁用防止将内容推送到非裸库的安全检查。
git config receive.denyCurrentBranch warn   # Warn when pushing to non-bare repo
git config receive.denyCurrentBranch ignore # Don't even bother warning

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接