为什么我不能推送到非裸存储库的签出分支?

时间:2016-09-21 12:30:58

标签: git github dvcs git-bare git-non-bare-repository

我对我创建的场景很困惑。我在Github上创建了一个存储库(让我们称之为A)并将代码推送到它。之后我将该存储库克隆到我的本地(让我们称之为B),这样我本地的来源就是远程回购A.

现在我从我的本地B克隆来创建另一个本地实例C.现在我有远程起源的C作为repo B而C的上游是A。

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import org.apache.commons.lang.math.NumberUtils;

public class RestServiceFilter implements ContainerRequestFilter {

    private static Logger _logger = Logger.getLogger(RestServiceFilter.class.getName());

    @Override
    public void filter(ContainerRequestContext crc)  {

        _logger.info("***** REST FILTER*********************");
        crc = updateURLForVersion(crc);
    }

    private ContainerRequestContext updateURLForVersion(ContainerRequestContext cr) {
        String baseURI = cr.getUriInfo().getBaseUri().toString();
        String requestURI = cr.getUriInfo().getRequestUri().toString();
        String pathURI = requestURI.substring(baseURI.length(), requestURI.length());
        String version = null;
        if (pathURI.startsWith("v") && pathURI.contains("/")) {
            String versionInURL = pathURI.substring(1, pathURI.indexOf("/"));
            if (NumberUtils.isNumber(versionInURL)) {
                version = "v" + versionInURL;
            }
        }
        if (StringUtil.isNullOrEmpty(version)) {
            version = ConfigReader.getinstance().get(Constants.REST_LATEST_VERSION);
            pathURI = version + "/" + pathURI;
            requestURI = baseURI + pathURI;
            try {
                cr.getUriInfo().getRequestUriBuilder().replacePath(requestURI);
//            cr.setRequestUri(new URI(requestURI));
            } catch (Exception ex) {
                ex.printStackTrace();
                Logger.getLogger(RestServiceFilter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return cr;
    }

这类似于分叉,但在这里我在客户端而不是服务器端创建了克隆。

现在,如果我尝试使用从C推送到其原点B:

A → B → C

然后我收到一条错误,指出我无法推送到非裸存储库。我知道推送到非裸存储库可能会导致本地远程不存在的提交丢失。

然而,这种情况与我将代码从B推送到A的情况不相似吗?

我很困惑,如果B到A是可能的,那么为什么不是C到B.

对于合并到A,我们可以推送到上游:

git push origin 

2 个答案:

答案 0 :(得分:6)

一些基本的东西

  • 从开发人员的角度来看,只要您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用于您需要做的工作。
  • 一般来说,你(通常)有分支机构。通常情况下,初学者不会创建分支,因为他正在学习,甚至可能不知道分支 - 尽管它们有很多原因。因此,他几乎总是会成为一名大师。 branch - 默认分支。

话虽如此,我们假设您修改了B中的一些文件。您可以git commit多次执行此操作,最后只需git push。或者你根本不做任何事情。但是你在主分支机构。

稍后,你修改C中的文件。你确实提交并尝试推送到A.记住:你在C的主分支上。git push有效!

然后,您也尝试将C推送到B. 它没有用。

结果:GIT将(不)字面上尖叫,警告您正在尝试玷污(更新)主分支HEAD指向另一个提交的非裸存储库B!如果他允许你进行推动,你将把GIT跟踪的历史记录弄乱在存储库B上。它不再知道B发生了什么!您甚至可能使用驻留在B上的相同名称覆盖该分支上的修改!所以不,如果两者都是非裸存储库,你就不能推送到B形式C!

现在怎么办?!我的世界会这样结束吗?!伟大的做了什么?! GIT怎么可能忽视他的主人的意愿?!这是纯粹的异端邪说!

解决方案

1 - 在B上有两个分支 - 主分支和临时分支。并将头指向临时分支。例如:

cd B                  # change to B's working directory
git branch temp       # create 'temp' branch
git checkout temp     # change from master branch to branch temp

2 - 现在,转到C工作目录(简称​​ wd )并使用B的内容进行操作。请注意,我认为B是远程的C(正如你在案例中提到的):

cd ../C               # change to C's working directory
git pull B master     # pulls B's modifications to C

3 - 用C修改你的文件。注意你在C&C的主分支上。然后,在提交C的修改后,将其推送到B的主人:

git push B master     # pushes C's mods to B's master branch

4 - 现在返回B wd 并将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指向一个命令。我使用较长的方法,因为你应该知道更长的方法;
  • 如前所述,如果您以后要使用它,请不要删除该分支。但我建议这样做是为了避免在拉/推或甚至合并时两个存储库中的临时分支出现问题。根据需要创建临时分支 - 使用终端历史记录非常简单 - 然后删除它;

答案 1 :(得分:0)

如果您使用

git clone --bare http://github.com/xxx/A B

然后你可以从C推到B.你当然不会 使用B进行工作,因为它是裸露的。

我仍然不明白为什么你想要“额外的”B回购?