0

我在玩 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_serverhehe_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) 我明白

一世。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@localhehe_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 相同

4

2 回答 2

1

Git 的术语在这里......不是很好。特别是,根本没有定义术语远程分支跟踪分支。有关定义的内容,请参见gitglossary

然而,人们有时会使用短语remote branch来表示远程跟踪分支名称在远程检查分支名称的结果。人们——以及 Git 书籍——有时使用短语tracking branch来表示具有上游集合的分支

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

不受上述所有影响的更通用的术语是ref(它是参考的缩写我倾向于在大多数情况下将其拼写出来)。如果你查看 Git 词汇表,你会发现这个词汇表被定义为:

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

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

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

  • git fetch https://github.com/owner/repo.git例如,如果您运行命令行,或者
  • 存储在远程名称下的 URL ,在本例中是hehe_server您使用后存储的 URL git fetch hehe_server

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

建立这种连接后,另一个 Git 会溢出它的所有 refs。1 您可以使用以下方法自己观察git ls-remote

git ls-remote hehe_server

此命令的输出是一组 ref 和哈希 ID,当 Git 呈现它们时,您的 Git 会看到它们。

无论如何,您的 Git 现在可以获取这些 ref 并按照fetch =设置的指示对其进行操作。每个设置都包含一个refspec参考规范在git fetch文档中有所描述,但主要包括:

  • 一个可选的前导+字符,意思是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@localhehe_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/*

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

这意味着要让它发挥作用,您必须:

  • 联系其他 Git
  • 获取他们所有分支名称的完整列表
  • 编写一组新的remote.hehe_server.fetch行,每个分支名称一行,使用您想要的映射:除了他们的master映射之外的所有内容,以及他们的master奇怪的映射。

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


1新的有线协议允许服务器端过滤 refs。如果没有此过滤,具有许多标签和/或分支的存储库可能会在您的 Git 与它进行有用的对话之前,在您的 Git 中喷出数兆字节的不需要的数据。但这——发射所有的 refs——是旧协议发生的事情。

于 2020-04-29T13:08:03.183 回答
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
于 2020-04-30T09:22:54.313 回答