【问题标题】:Repo and its clone disagree about HEAD pointer回购及其克隆不同意 HEAD 指针
【发布时间】:2016-09-30 04:43:15
【问题描述】:

我正在尝试将我的主分支重命名为“liveBranch”,创建一个新分支(“devBranch”),然后在同一台计算机上的另一个文件夹中克隆存储库(称为存储库 A)(称为存储库 B) .但是当我这样做时,如果我在 repo B 上执行 git branch -a,它会显示 repo A 的 HEAD 指向“devBranch”,而 repo A 上的 git branch -a 声称“liveBranch”已签出。

这是我的具体步骤(注意:repoA 是一个非空目录):

cd path/to/repoA
git init
git add .
git commit
git branch -m master liveBranch
git branch devBranch
git clone path/to/repoA path/to/repoB 
cd path/to/repoB

在 repo B 中运行 git branch -a 返回:

* devBranch
  remotes/origin/HEAD -> origin/devBranch
  remotes/origin/devBranch
  remotes/origin/liveBranch

在 repo A 中运行 git branch -a 时返回:

  devBranch
* liveBranch

我认为这可能是因为这两个分支实际上都指向同一个提交,所以这两个仓库在技术上都不是错误的。因此,我在 repo A 中的一个分支上进行了提交以推进分支并在 repo B 中做了一个git pull,但断开连接仍在发生(repo B 和 repo A 不同意 repo A 已签出的分支)。

【问题讨论】:

  • 我尝试了您的示例,并且回购 B 中的 git branch -a 说 liveBranch 已签出。 git 版本 2.8.2
  • 我正在运行 git 版本 1.7.10。不过,torek 的回答重现了我对 2.8.1 的问题。

标签: git git-branch git-clone git-remote


【解决方案1】:

您的“确切步骤”有些问题,因为如果我首先尝试重现问题:

cd path/to/repoA
git init
git add .
git commit

我的系统上有这个:

$ cd /tmp; mkdir btest; cd btest
$ mkdir repoA; cd repoA
$ git init
Initialized empty Git repository in /tmp/btest/repoA/.git/
$ git add .
$ git commit
On branch master

Initial commit

nothing to commit
$ 

看起来好像你在一个已经存在并且有一些提交的存储库中执行你的git init,否则master 在这一点上仍然是一个未出生的分支。无论如何,现在我稍微改变一下你的步骤:

$ echo 'dummy repo for testing' > README
$ git add .
$ git commit -m initial
[master (root-commit) 82f36fb] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ git branch -m master liveBranch
$ git branch devBranch
$ git branch
  devBranch
* liveBranch
$ 

现在让我们尝试将其克隆到 /tmp/btest/repoB:

$ git clone /tmp/btest/repoA /tmp/btest/repoB
Cloning into '/tmp/btest/repoB'...
done.
$ cd ../repoB
$ git status
On branch liveBranch
Your branch is up-to-date with 'origin/liveBranch'.
nothing to commit, working directory clean
$ 

它正在按照你想要的方式工作。

让我们采用不同的方法来重复该问题,首先删除两个测试存储库,然后使用指向 devBranch 的 HEAD 创建一个新存储库,然后克隆该存储库:

$ cd /tmp/btest
$ rm -rf *
$ mkdir repoA; cd repoA; git init
Initialized empty Git repository in /tmp/btest/repoA/.git/
$ echo > README; git add README; git commit -m initial
[master (root-commit) 8278cc4] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ git branch -m master devBranch
$ cd ..; git clone repoA repoB; (cd repoB; git status; git branch -A)
Cloning into 'repoB'...
done.
On branch devBranch
Your branch is up-to-date with 'origin/devBranch'.
nothing to commit, working directory clean
* devBranch
  remotes/origin/HEAD -> origin/devBranch
  remotes/origin/devBranch
$ 

所以我们的 repoB 处于合适的状态。现在我们改变 repoA 使它有 HEAD 指向 liveBranch:

$ (cd repoA; git checkout -b liveBranch; git branch)
Switched to a new branch 'liveBranch'
  devBranch
* liveBranch
$ 

如果我们在 repoB 中向 git 请求 git pull,我们现在应该期望发生什么?好吧,让我们看看会发生什么(注意,这是 Git 2.8.1 版本;1.8.4 之前的行为在某些情况下会有点不同):

$ cd repoB; git pull
From /tmp/btest/repoA
 * [new branch]      liveBranch -> origin/liveBranch
Already up-to-date.
$ git branch -a
* devBranch
  remotes/origin/HEAD -> origin/devBranch
  remotes/origin/devBranch
  remotes/origin/liveBranch
$ 

现在让我们尝试一些不同的方法,即在 repoB 中运行 git fetch,以及 git ls-remote

$ git fetch
$ git branch -a
* devBranch
  remotes/origin/HEAD -> origin/devBranch
  remotes/origin/devBranch
  remotes/origin/liveBranch
$ git ls-remote
From /tmp/btest/repoA
8278cc44d45cad50f34dc2c788cd9df7bf9375ec    HEAD
8278cc44d45cad50f34dc2c788cd9df7bf9375ec    refs/heads/devBranch
8278cc44d45cad50f34dc2c788cd9df7bf9375ec    refs/heads/liveBranch

显然git pullgit fetch 都没有读取新的远程HEAD 状态,或者如果是,则回退到名称到ID 的转换。让我们用新的提交更新 repoA 并重新获取:

$ (cd ../repoA; git commit -m update --allow-empty)
[liveBranch 2234cf1] update
$ git fetch
remote: Counting objects: 1, done.
remote: Total 1 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (1/1), done.
From /tmp/btest/repoA
   8278cc4..2234cf1  liveBranch -> origin/liveBranch
$ git branch -a
* devBranch
  remotes/origin/HEAD -> origin/devBranch
  remotes/origin/devBranch
  remotes/origin/liveBranch
$ git ls-remote
From /tmp/btest/repoA
2234cf14c9f7c63785e8fe31b7e5f37bcaf51823    HEAD
8278cc44d45cad50f34dc2c788cd9df7bf9375ec    refs/heads/devBranch
2234cf14c9f7c63785e8fe31b7e5f37bcaf51823    refs/heads/liveBranch
$ 

所以,是的,Git 在初始克隆后根本无法更新 remotes/origin/HEAD,至少在使用绝对路径时是这样。将 URL 更改为 file:///tmp/btest/repoA 没有区别:

$ git config remote.origin.url file:///tmp/btest/repoA
$ git fetch
$ git branch -a
* devBranch
  remotes/origin/HEAD -> origin/devBranch
  remotes/origin/devBranch
  remotes/origin/liveBranch

快速查看源代码表明,在最初的clone 步骤之后,git 从不费心更新remotes/origin/HEAD

【讨论】:

  • 奇妙的探索,非常感谢torek。您在回答开始时的假设是正确的:我忘了说明 repoA 是一个现有的非空目录(现在用注释编辑)。
【解决方案2】:

似乎您可能正在一个已经存在并且有一些提交的存储库中执行您的git init,否则master 在这一点上仍然是一个未出生的分支。

即使 master 未出生,您仍然可以(现在,Git 2.30,Q1 2021)重命名它:

这是用户培训的一部分,为他们将来更改 init.defaultBranch 配置变量做好准备。

参见Johannes Schindelin (dscho)@commit 675704ccommit cc0f13ccommit cfaff3acommit 1296cbe(2020 年 12 月 11 日)。
(由 Junio C Hamano -- gitster -- 合并到 commit 772bdcd,2020 年 12 月 18 日)

branch -m: 允许重命名尚未诞生的分支

签字人:约翰内斯·辛德林

在接下来的一次提交中,我们想给用户一些关于初始分支名称以及如何修改它的建议。

为此,如果git branch -m <name>(man) 在新初始化的存储库中工作而无需任何提交,那就太好了。
就这样吧。

测试表明实际效果:

test_expect_success 'branch -m with the initial branch' '
    git init rename-initial &&
    git -C rename-initial branch -m renamed &&
    test renamed = $(git -C rename-initial symbolic-ref --short HEAD) &&
    git -C rename-initial branch -m renamed again &&
    test again = $(git -C rename-initial symbolic-ref --short HEAD)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 2016-06-05
    • 2021-09-01
    • 1970-01-01
    相关资源
    最近更新 更多