“远程分支”,“远程跟踪分支”和“跟踪分支”可以有不同的名称吗?

时间:2020-04-29 12:18:41

标签: git git-branch refspec git-refspec

我正在玩git。


当前状态:

1)我的本地仓库有一个分支master_local。

2)远程仓库有一个分支master_remote。 (遥控器的名称是hehe_server)

3)我的本地.git/config看起来像

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "hehe_server"]
    url = /path/to/git/remote_main.git
    fetch = +refs/heads/*:refs/remotes/hehe_server/*
[branch "master_local"]
    remote = hehe_server
    merge = refs/heads/master_remote

4)当我运行git fetch时,git会将master_remote@hehe_server提取到hehe_server/master_remote@local (aka, /.git/refs/remotes/hehe_server/master_remote@local)

5)当我运行git branch -vv时,它说

* master_local 06022cf [hehe_server/master_remote] my_commit_msg

6)我理解

i。 master_local@local被称为“跟踪分支”

ii。 master_remote@hehe_server被称为“远程分支”

iii。 hehe_server/master_remote@local被称为“远程跟踪分支”

7)我的git版本是git版本2.23.0。

8)我正在使用Mac 10.15.1


我的问题:

我想将hehe_server/master_remote@local重命名为hehe_server/master_haha@local,同时保持其他所有内容不变。我可以这样做吗?


我的实验:

我尝试使用fetch =中的.git/config行,但这确实令人困惑...

测试1

fetch = +refs/heads/*:refs/remotes/hehe_server/*更改为fetch = +refs/heads/master_local:refs/remotes/hehe_server/master_remote

结果1

git branch -vv说

* master_local 06022cf my_commit_msg

似乎master_local不再跟踪master_remote。。我不明白。

测试2

fetch = +refs/heads/*:refs/remotes/hehe_server/*更改为fetch = +refs/heads/master_local:refs/remotes/hehe_server/master_haha

结果2

与结果1相同

2 个答案:

答案 0 :(得分:1)

这里的Git术语不是那么好。特别是,根本没有定义术语远程分支跟踪分支。有关定义,请参见the gitglossary

人们确实有时会使用短语远程分支来表示远程跟踪分支名称在远程计算机上检查分支名称的结果< / em>。人们(以及Git书)有时使用短语 tracking branch 来表示具有上游设置的分支

您的远程跟踪分支定义与Gitglossary中的定义匹配。我不喜欢这个词,因为它导致人们放弃形容词 tracking 并将其称为 remote分支,不同的人对此有不同的解释。 (我更喜欢称其为远程跟踪名称,尽管这并不是真正的改进。主要的改进(如果有的话)在于不再使用“分支”一词。: -))

一个不受上述所有影响的更通用的术语是 ref (这是 reference的缩写; 我倾向于将其大部分时间)。如果您查看Git词汇表,将会看到这一术语定义为:

refs/开头的名称(例如refs/heads/master)指向对象名称或另一个引用(后者称为符号引用)。为了方便起见,有时在将ref用作Git命令的参数时会缩写它。有关详细信息,请参见gitrevisions [7]。引用存储在存储库中。

无论如何:是的,您可以按照您的建议对名称进行任意修改。 fetch =中的.git/config行确定如何修改每个 ref

运行git fetch时,该过程的第一步是您的Git调用其他Git。您的Git到达该Git的URL来自:

  • 命令行,例如,如果您运行git fetch https://github.com/owner/repo.git,或者
  • remote 的名称存储的URL,在这种情况下,因为您使用hehe_server,所以存储在git fetch hehe_server下。

(还有其他几种指定存储库URL的方法,因为在发明遥控器之前有很多历史记录。这是两种常见方法。)

建立连接后,另一个Git就会溢出所有引用。 1 您可以使用git ls-remote自己观察一下:

git ls-remote hehe_server

此命令的输出是您的Git在他们的Git呈现它们时看到的ref和哈希ID的集合。

无论如何,您的Git现在可以按照fetch =设置的指示使用这些参考并对其进行操作。每个设置都包含一个 refspec 。引用规范在the git fetch documentation中进行了描述,但主要由以下内容组成:

  • 可选的前导+字符,表示 force ;
  • 来源名称或模式;
  • 冒号:;和
  • 目的地 名称或模式。

源名称或模式与另一个Git呈现的名称匹配。生成的目标名称或模式用于构造您的 Git将创建或更新的名称(或者,如果没有输入名称匹配,则使用--prune删除)。

这里有一些奇怪的约束。特别是,如果您设置了与单个目标匹配的多个源名称,或者与多个目标匹配的单个源,则无法使用。例如:

+refs/heads/master:refs/remotes/hehe_server/foo
+refs/heads/master:refs/remotes/hehe_server/bar

导致一个来源master映射到两个输出,并且:

[remote "hehe_server"]
    fetch = +refs/heads/master:refs/remotes/hehe_server/foo
    fetch = +refs/heads/develop:refs/remotes/hehe_server/foo

导致两个来源masterdevelop映射到单个输出。两者都无法有效地处理。

我想将hehe_server/master_remote@local重命名为hehe_server/master_haha@local,同时保持其他所有内容不变。我可以这样做吗?

是的,但是大多数不是。特别是,如果您想带他们的refs/heads/master并将其命名为refs/remotes/hehe_server/master_haha,那么这部分很简单:

fetch = +refs/heads/master:refs/remotes/hehe_server/master_haha

可以解决问题。但是,如果您现在想取所有剩余的名称并以通常的方式处理它们:

fetch = +refs/heads/*:refs/remotes/origin/*

您已经告诉Git refs/heads/master应该在本地成为两个名称,因为第二行将名称映射到refs/remotes/origin/master

这意味着要使其正常工作,您必须:

  • 联系其他Git
  • 获取其分支名称的 all 的完整列表
  • 编写一组新的remote.hehe_server.fetch行,每个分支名称一行,并具有所需的映射:除了它们的master映射和往常一样,master映射之外的所有内容。< / li>

每次服务器上的分支名称集更改时,都必须重复此过程。


1 新的有线协议允许在服务器端过滤引用。如果没有这种过滤,具有许多标签和/或分支的存储库可能会在您的Git上进行不必要的对话之前,在您的Git上喷出数兆字节的有害数据。但这会发出所有参考,这是旧协议发生的情况。

答案 1 :(得分:0)

这不是答案。我将测试脚本放在这个答案中,以供其他人了解整个情况。

#!/bin/bash
echo "
change branches' names
    refs/heads/master_local 
    refs/remote/hehe_server/master_haha
    master_remote@remote
"
PATHA=/path/to/an/empty/folder/


# Any subsequent(*) commands which fail will cause the shell script to exit immediately
set -e

# Makes the bash script to print out every command before it is executed except echo
trap '[[ $BASH_COMMAND != echo* ]] && echo "++++++RUN COMMAND: Line ${LINENO}: $BASH_COMMAND --- RESULT IS A BELOW"' DEBUG




cd $PATHA



echo "make a bare repo"
git --git-dir=$PATHA/remote_main.git init --bare


echo "clone"
cd $PATHA
git clone $PATHA/remote_main.git main --origin hehe_server


echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "commit and push in master"
cd $PATHA/main
echo "test@master" > $PATHA/main/index.js
git add .
git commit -m "commit and push in master"
git push


echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "commit and push in feature"
git checkout -b feature
echo "test@feature" > $PATHA/main/index.js
git add .
git commit -m "commit and push in feature"
git push -u hehe_server feature
git checkout master


echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "commit and push in release"
git checkout -b release
echo "test@release" > $PATHA/main/index.js
git add .
git commit -m "commit and push in release"
git push -u hehe_server release
git checkout master



echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "master@local --> master_local, master@hehe_server --> master_remote@hehe_server"

echo "# create and switch to the release branch"
git checkout -b master_local master

echo "# push the master_local branch to the remote and track it"
git push -u hehe_server master_local:master_remote

echo "# delete local master"
git branch -d master

echo "# delete remote master"
git --git-dir=$PATHA/remote_main.git symbolic-ref HEAD refs/heads/master_remote
git push --delete hehe_server master



echo "------------------------------------------------------------------------------------------------------------------------------------"
echo "hehe_server/master_remote@local --> hehe_server/master_haha@local"

echo "remove fetch= section first"
git config --unset remote.hehe_server.fetch
cat .git/config
echo "add first line for fetch="
git config --add remote.hehe_server.fetch "+refs/heads/master_remote:refs/remotes/hehe_server/master_haha"
echo "add second line for fetch="
git config --add remote.hehe_server.fetch "+refs/heads/*:refs/remotes/hehe_server/*"
cat .git/config


echo "check"
echo "see torek's warning: But if you now want to take all the remaining names and handle them in the usual way ...."
git branch -vv  # outputs: * master_local 0870a94 [hehe_server/master_haha: gone] xxx
git fetch
git branch -vv  # outputs: * master_local 0870a94 [hehe_server/master_haha] xxx


echo "why doesn't `git fetch --prune` remove the hehe_server/master_remote@local?"
ls -lah $PATHA/main/.git/refs/remotes/hehe_server
git fetch --prune
ls -lah $PATHA/main/.git/refs/remotes/hehe_server