昨天,我发了一个关于如何从我的一台机器上克隆Git仓库的问题,22。
我现在能够成功地从我的源(192.168.1.2)克隆一个 Git 仓库到我的目的地(192.168.1.1)。
但当我对一个文件进行编辑,进行 "git commit -a -m "test" "和 "git push "时,我在目的地(192.168.1.1)得到了这个错误。
git push
[email protected]'s password:
Counting objects: 21, done.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 1010 bytes, done.
Total 11 (delta 9), 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 git+ssh://[email protected]/media/LINUXDATA/working
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'git+ssh://[email protected]/media/LINUXDATA/working'
我使用了两个不同版本的Git(远程的是1.7,本地的是1.5)。这可能是一个原因吗?
我在开始学习Git时,也刚刚遇到了同样的错误。其他的一些答案显然不适合刚接触Git的人!
(我打算用非技术术语来表达我的意思。) 总之,现在的情况是你有两个仓库,一个是你第一次做的原始仓库,另一个是你刚做的工作仓库。
现在你在你的工作仓库里,使用的是"master"分支。但你也碰巧在你的原始版本库中登录到了同样的"master"分支。现在,由于你在原始仓库中登录,Git 担心你会搞砸,因为你可能在原始仓库中工作而把事情搞砸了。所以你需要回到原始仓库,做一个"git checkout someotherbranch",现在你可以顺利地推送了。
我希望这有帮助。
错误信息描述了发生了什么。更多现代版本的 Git 拒绝通过推送来更新一个分支,如果该分支被签出。
在两个非空白仓库之间工作,最简单的方法就是
始终通过 pull(或 fetch and merge)来更新仓库,或者,如果你不得不这么做的话。
推送到一个单独的分支(导入分支),然后将该分支合并到远程机器上的主分支。
之所以有这样的限制,是因为推送操作只对远程的 Git 仓库进行操作,它不能访问索引和工作树。因此,如果允许的话,对已签出的分支进行推送会改变 HEAD
**,使其与远程仓库的索引和工作树不一致。
这将使我们很容易意外地提交一个修改,从而撤销所有推送的修改,也使我们很难区分任何未提交的本地修改和推送移动HEAD'而导致的新
HEAD'、索引和工作树之间的差异。
你不能推送到版本库的一个已被签出的分支,因为这会对版本库的用户造成混乱,很可能会导致**数据和历史记录的丢失。 但你可以推送到同一个版本库的任何其他分支。
由于裸仓库永远不会有任何分支被签出,所以你总是可以推送到裸仓库的任何分支。
**根据你的需求,有多种解决方案。
使用裸仓库
正如建议的那样,如果在一台机器上,你不需要工作目录,你可以移动到裸仓库。 为了避免对版本库造成干扰,你可以直接克隆它。
machine1$ cd ..
machine1$ mv repo repo.old
machine1$ git clone --bare repo.old repo
现在你可以把所有你想要的东西推送到和以前一样的地址。
推送到一个未结账的分支机构
但如果你需要检查远程<远程>
上的代码,那么你可以使用一个特殊的分支来推送。
比方说,在你的本地仓库中,你已经调用了你的远程origin
,并且你在分支master上。
那么你可以这样做
machine2$ git push origin master:master+machine2
那就需要在你进入 "原点 "远程仓库的时候合并它。
machine1$ git merge master+machine2
当一个分支被签出时,提交将添加一个新的提交,并将当前分支的头部作为其父级,并将该分支的头部移动到新的提交中。
所以
A ← B
↑
[HEAD,branch1]
成为
A ← B ← C
↑
[HEAD,branch1]
但如果有人能在中间推送到那个分支,用户就会让自己进入git所谓的分离头模式。
A ← B ← X
↑ ↑
[HEAD] [branch1]
现在,用户已经不在分支1中了,而没有明确要求查看另一个分支。 更糟糕的是,用户现在已经在任何分支之外了,任何新的提交都只会是纠缠。
[HEAD]
↓
C
↙
A ← B ← X
↑
[branch1]
假设,如果这时,用户签出了另一个分支,那么这个悬而未决的提交就成了Git的垃圾收集器的游戏。
你可以通过在目标服务器上编辑.git/config
来绕过这个"限制"。
通过编辑目标服务器上的.git/config
。
添加以下内容以允许推送 git 仓库,即使它是 "签出"。
[receive]
denyCurrentBranch = warn
或
[receive]
denyCurrentBranch = false
第一种会允许推送,同时警告可能会弄乱分支,而第二种则只是悄悄地允许。
这可以用来"部署"。 代码到一个不是用来编辑的服务器上。 这不是最好的方法,但却是一个快速部署代码的方法。
git config --local receive.denyCurrentBranch updateInstead
。
https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155
在服务器版本库上使用这个功能,如果没有发生未跟踪的覆盖,它也会更新工作树。
我已经编译了 Git 2.3,并尝试了一下。 使用示例。
git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead
cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master
cd ../server
ls
产出:
a
b
Yay,b
被推了!
我也有同样的问题。 对我来说,我使用Git推送将代码移动到我的服务器上。 我从不在服务器端修改代码,所以这是安全的。
在版本库中,你要推送的内容是
git config receive.denyCurrentBranch ignore
这将允许你在它是一个工作副本的时候修改版本库。
在运行 Git 推送后,进入远程机器并输入以下内容:{{6937918}}}。
git checkout -f
这将使你推送的更改反映在远程机器的工作副本中。
请注意,如果你在推送到的工作副本中进行了更改,这并不总是安全的。
你可能做了什么导致这种情况:。
这种事情发生在你去敲打一个小程序的时候。 你要改变一些已经在运行的东西,所以你施展了你的3级永久不可修复咒。
machine1:~/proj1> git init
然后你开始添加/提交。 但*后,项目开始变得越来越多,你想从另一台电脑(比如你的家用电脑或笔记本电脑)上进行工作,所以你做了一些类似于
machine2:~> git clone ssh://machine1/~/proj1
然后它就会克隆,一切看起来都很好,所以你就在2号机上处理你的代码。
然后... 你试着从2号机推送你的提交,然后你收到标题中的警告信息。
之所以会有这样的消息,是因为你从git repo里拉出来的东西,本来是打算只用于机器1上的那个文件夹的。
你可以克隆它就好了,但推送会导致问题。
The "correct"
的方式是用一个"bare"
repo,就像有人建议的那样。
裸仓库的设计并不是为了让任何工作都在其中进行,而是为了协调多个来源的提交。
这就是为什么顶配答案建议在你git config --bool core.bare true
之后,删除除.git文件夹以外的所有文件/文件夹。
澄清顶配答案:该答案的很多评论都说像"我没有从机器1中删除非.git文件,我仍然能够从机器2提交"。
这'是对的。
然而,这些其他文件已经完全"divorced"
从git repo中分离出来了。
去试试那里的git status
,你应该会看到类似于"致命的。
这个操作必须在工作树中运行"。
所以,删除文件的建议并不是为了让机器2的提交能够*工作。
而是为了让你不会感到困惑,以为git还在跟踪这些文件。
但是,如果你还想处理机器1上的文件,删除文件是个问题,不是吗?
**所以,你到底应该怎么做?
要看在1号机和2号机上还想做多少工作......。
如果你已经完成了在机器1上的开发,并把所有的开发工作都转移到机器2上......就按上面的答案建议去做。
git config --bool core.bare true
然后,可以选择从该文件夹中删除除.git以外的所有文件/文件夹,因为这些文件/文件夹没有被跟踪,很可能会造成混乱。
如果你在 machine2 上的工作只是一次性的,而且你不需要在那里继续开发......,那就不要去做裸回购了。 只需将你的文件从机器2上的ftp/rsync/scp/etc. 在机器1的文件上加上机器2的文件,从机器1提交/推送,然后从机器2删除文件。 其他人建议创建一个分支,但我认为如果你只是想从另一台机器上一次性合并一些开发工作,那就有点乱了。
如果你需要同时在机器1和机器2上继续开发......,那么你需要正确地设置事情。 你需要把你的repo转换为裸机,*你需要在机器1上做一个克隆,供你工作。 最快的方法可能是进行以下操作
machine1:~/proj1> git config --bool core.bare true
machine1:~/proj1> mv .git/ ../proj1.git
machine1:~/proj1> cd ..
machine1:~> rm -rf proj1
machine1:~> git clone proj1.git
machine1:~> cd proj1
非常重要:因为你已经将 repo 的位置从 proj1 移到了 proj1.git,你需要在机器 2 的 .git/config 文件中更新。 之后,你就可以在2号机上提交你的改动了。 最后,我尽量把裸仓库放在一个中心位置,远离我的工作树(即 不要把 'proj1.git' 和'proj1.git'放在同一个父文件夹中)。) 我建议你也这样做,但我想让上面的步骤尽可能简单。
通过几个设置步骤,您可以使用一个单行本轻松地部署更改到您的网站,如
git push production
这很好,也很简单,而且你不需要登录到远程服务器,也不需要进行拉取什么的。 请注意,如果你不使用你的生产分支作为工作分支,这将是最好的工作!(OP是在稍微不同的背景下工作,我想@Robert Gould'。 (OP的工作环境略有不同,我认为@Robert Gould'的解决方案很好地解决了这个问题。 这个解决方案更适合部署到远程服务器上)。)
首先,你需要在服务器上的某个地方建立一个裸仓库,在webroot之外。
mkdir mywebsite.git
cd mywebsite.git
git init --bare
然后创建文件hooks/post-receive
。
#!/bin/sh
GIT_WORK_TREE=/path/to/webroot/of/mywebsite git checkout -f
并使该文件可执行。
chmod +x hooks/post-receive
在你的本地机器上。
git remote add production [email protected]:mywebsite.git
git push production +master:refs/heads/master
一切就绪!现在,你可以使用 "git推送生产 "来部署你的修改。 现在,你可以使用 "git push production "来部署你的修改了。
这个解决方案的功劳归于http://sebduggan.com/blog/deploy-your-website-changes-using-git/。 请看那里有更详细的解释'是怎么回事。
git pull; git pull; git push
git push origin master: foo
并将其合并到远程(通过git
或[pull-request][1])
git merge foo
rebase
改变提交内容)。git push origin master -f
如果仍然被拒绝,则在**远程仓库上禁用denyCurrentBranch
。
git config receive.denyCurrentBranch ignore
我在使用 Git 同步 Android 手机和笔记本电脑上的仓库时也遇到了同样的问题。 我的解决办法是按照 @CharlesBailey 的建议,用拉的方式代替推的方式。
git push origin master
在安卓版本库上的推送失败了,跟@hap497的错误信息一样,因为推送到了版本库的nonbare checkout + working-copy。
笔记本仓库上的git pull droid master
和working-copy对我来说是可行的。
当然,你需要之前运行过git remote add droid /media/KINGSTON4GB/notes_repo/
之类的东西。
检查目标项目中的.git/config
。
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[receive]
denyCurrentBranch = updateInstead
如果 "core.bare "为false,你可以将其设置为true: bare`是false,你可以把它设置为true。
$ git config core.bare true
然后在你的本地推送到远程。
git push remote_repo // suppose the destination repo is remote_repo
它将会成功,在 remote_repo 中你可以检查 git 版本。
$ git log -1
commit 0623b1b900ef7331b9184722a5381bbdd2d935ba
Author: aircraft < [email protected]>
Date: Thu May 17 21:54:37 2018 +0800
现在你不能在你的"工作空间"中使用git。
$ git status
fatal: This operation must be run in a work tree
你应该把bare.bare
设置为false。
$ git config core.bare false
旧版本的 Git 允许推送到非虚拟仓库的当前签出分支。
但事实证明,这样做是非常令人困惑的。 所以他们添加了你所看到的警告信息,这也是非常令人困惑的。
如果第一个仓库只是作为一个服务器,那么按照其他答案的建议将其转换为裸仓库就可以了。
然而,如果你需要在两个都在使用的仓库之间建立一个共享分支,你可以通过下面的设置来实现它
Repo1 - 将作为服务器,也用于开发。
Repo2----将仅用于开发
设置Repo1的方法如下
创建一个分支来分享工作。
git branch shared_branch
为了安全起见,您还应该创建一个 $(REPO).git/hooks/update,以拒绝对 shared_branch 以外的任何改动,因为您不希望别人对您的私有分支进行破坏。
repo1/.git/hooks (GIT_DIR!)$ cat update
#!/bin/sh
refname="$1"
oldrev="$2"
newrev="$3"
if [ "${refname}" != "refs/heads/shared_branch" ]
then
echo "You can only push changes to shared_branch, you cannot push to ${refname}"
exit 1
fi
现在在 repo1 中创建一个本地分支,你将在那里进行你的实际工作。
git checkout -b my_work --track shared_branch
Branch my_work set up to track local branch shared_branch.
Switched to a new branch 'my_work'
(可能需要 "git config --global push.default upstream "才能使 "git push "发挥作用)
现在,你可以用以下方法创建repo2
git clone path/to/repo1 repo2
git checkout shared_branch
在这一点上,你已经把repo1和repo2都设置成可以在本地分支上工作,并从repo1中的shared_branch
中推送和拉取,而不需要担心错误信息或工作目录在repo1中不同步。
不管你用什么正常的工作流程,都应该可以。
这里有一个测试,你可以做一个测试,看看bare
服务器的东西是如何工作的。
想象一下,你有一个工作站和一个服务器,上面有一个实时站点,你想不时地更新这个站点(这也适用于两个开发人员通过一个裸露的中间人来回发送工作的情况)。
在你的本地电脑上建立一个目录,然后cd
进入,然后执行这些命令。
# initialization
git init --bare server/.git
git clone server content
git clone server local
server
目录(注意最后的.git)。
这个目录将只作为你的版本库文件的容器。然后将你的服务器仓库克隆到一个新创建的content
目录中。
这是你的实时/生产目录,将由你的服务器软件提供服务。
3.前两个目录在你的服务器上,第三个是你工作站上的本地目录。
现在这里是基本的工作流程。
local
目录,创建一些文件并提交。
最后把它们推送到服务器上。git commit -av git push origin master
content
目录,更新服务器'的内容。git pull
content
可能是另一个开发者也可以推送到服务器上,local
因为你可能从他那里拉来。