一些基础知识
每当你使用git clone
时,从开发者的角度来看,你会想在刚克隆下来的代码上进行工作。因此,GIT会给你一个“工作树”来进行操作。它被称为树,因为当你考虑到所有的提交和分支,并把它们放在一个图形上时,它就像一棵树。
克隆的存储库称为非裸存储库。要创建一个非裸存储库,只需执行一个简单的git init
- 这就是原始程序员使用GIT开始跟踪克隆代码的方式。你也可以将其克隆到一个裸存储库中,但它的细节和有用性应该在一个关于它的适当问题的答案中解释清楚。
裸存储库不包含工作树。它只是用来存储你的代码的 - 如果你愿意的话,可以将其视为由GIT管理的代码服务器。要创建一个裸存储库,只需执行一个简单的git init --bare name_of_repository.git
。它将创建一个名为name_of_repository.git的目录,其中包含GIT所需的所有文件。git扩展名只是一个惯例,它不是必需的,可以是任何东西或根本没有。
GIT中有一种类似于指针的东西,称为HEAD。它指向你正在工作的分支中活动的最新提交。
分支就像你从远程存储库拉下来的代码的“不同副本”(可能有不同的修改或没有)。它具有开发人员认为合适的任何名称。它们很有用,因为你可以在不担心当前由你或其他人开发的代码的情况下,处理不同的功能或修复不同的问题。稍后,你总是可以将所有内容合并到主分支 - 通常是master - 然后删除那些不再需要的已合并分支。
GIT尽力避免不同位置或分支的文件版本之间的问题。因此,在某些情况下,它确定为至少混乱时,它不会允许你进行git push
。GIT永远不会错,因为它要求你检查、更改或强制执行你正在做的事情。因此,任何错误都不是GIT的错,而只是你自己的错。
理解情况
让我们考虑以下情况:
- A仓库是一个裸仓库。B和C仓库都是非裸仓库。这意味着A没有工作目录,仅用于存储。B和C用于需要完成的工作。
- 一般来说,你(通常)会有分支。通常初学者不会创建分支,因为他正在学习,甚至可能还不知道分支——尽管它们有很多用处。所以他几乎总是在“主”分支上——默认分支。
话虽如此,假设你在B中修改了一些文件。你可以进行任意次数的git commit
,甚至在最后进行git push
。或者你什么也不做。但你在主分支上。
稍后,你在C中修改了文件。然后你提交并尝试推送到A。记住:你在C的主分支上。 git push
成功了!
然后,你尝试将C推送到B。 它不起作用。
结果:GIT会(不会)直接警告你,指出你试图更新非裸仓库B的主分支,而其HEAD指向另一个提交!如果它让你进行推送,你将破坏GIT在仓库B上跟踪的历史记录。它将不知道B发生了什么!你甚至可能会用与B上同名分支上的相同名称覆盖该分支上的修改!因此,如果两个仓库都是非裸仓库,则无法从C推送到B!
现在怎么办?我的世界就这样结束了吗?伟大的I能做什么?GIT如何忽视他主人的愿望?这是纯粹的异端邪说!
解决方案
1 - 在B上有两个分支——主分支和临时分支。并使HEAD指向临时分支。例如:
cd B
git branch temp
git checkout temp
2 - 现在,进入C工作目录(简称wd),并拉取B的内容。请注意,我假设B是C的远程仓库(根据您提供的情况):
cd ../C
git pull B master
3 - 在C中修改您的文件。请注意,您正在C的主分支上。然后,在提交C的修改后,将其推送到B的主分支:
git push B master
4 - 现在回到 Bwd,将 HEAD 指向主分支:
cd ../B # change to B's working directory
git checkout master # change from temp branch to branch master
5 - 如果您不再需要临时分支,可以将其删除:
git branch -d temp # delete branch temp
6 - 如果你正在对C语言进行新的修改,那么你不需要同时进行步骤4和5。如果你这样做,每当你想要在C语言中进行修改时,你都需要事先执行步骤1和2。
这样就解决了你的问题! 可能……
澄清和加强
git branch name_of_the_branch
创建一个新的分支;
git checkout name_of_the_branch
将HEAD指向这个新的分支;
git checkout -b name_of_the_branch
在一个命令中创建一个分支并将HEAD指向它。我使用了较长的方法,因为你也应该知道较长的方法;
- 如前所述,如果您以后还要使用该分支,请勿删除该分支。但我建议这样做是为了避免在拉取/推送或合并时出现两个存储库中的临时分支问题。根据需要创建临时分支 - 使用终端历史记录相当容易 - 然后在之后将其删除;