ChatGPT解决这个技术问题 Extra ChatGPT

在 git 中,有没有一种简单的方法可以将不相关的分支引入存储库?

今天在帮助朋友解决 git 问题时,我不得不介绍一个需要与 master 分支完全分开的分支。这个分支的内容确实与在 master 分支上开发的内容不同,但它们将在以后合并到 master 分支中。

我记得阅读 John Wiegley 的Git from the bottom up,分支本质上是遵循特定约定的提交的标签,以及提交如何绑定到文件树以及可选地绑定到父提交。我们使用 git 的管道创建了对现有存储库的无父提交:

所以我们摆脱了索引中的所有文件......

$ git rm -rf .

...从压缩包中提取目录和文件,将它们添加到索引中...

$ git add .

...并创建了一个树对象...

$ git write-tree

git-write-tree 告诉我们创建的树对象的 sha1sum。)

然后,我们提交了树,没有指定父提交......

$ echo "Imported project foo" | git commit-tree $TREE

git-commit-tree 告诉我们创建的提交对象的 sha1sum。)

...并创建了一个指向我们新创建的提交的新分支。

$ git update-ref refs/heads/other-branch $COMMIT

最后,我们返回 master 分支继续在那里工作。

$ git checkout -f master

这似乎按计划进行。但这显然不是我向刚开始使用 git 的人推荐的那种程序,委婉地说。有没有一种更简单的方法来创建一个与存储库中迄今为止发生的一切完全无关的新分支?


C
Community

有一个新功能(自 V1.7.2 起)使此任务比其他任何答案中的任务更高级一些。

git checkout 现在支持 --orphan 选项。从 man page

git checkout [-q] [-f] [-m] --orphan <new_branch> [<start_point>]

创建一个名为 的新孤立分支,从 开始并切换到它。在这个新分支上进行的第一次提交将没有父母,它将成为与所有其他分支和提交完全断开的新历史的根。

这并没有完全满足询问者的要求,因为它从 <start_point> 填充索引和工作树(因为这毕竟是一个结帐命令)。唯一需要的其他操作是从工作树和索引中删除任何不需要的项目。不幸的是,git reset --hard 不起作用,但可以使用 git rm -rf . 代替(我相信这相当于其他答案中给出的 rm .git/index; git clean -fdx)。

总之:

git checkout --orphan newbranch
git rm -rf .
<do work>
git add your files
git commit -m 'Initial commit'

我没有指定 <start_point>,因为它默认为 HEAD,无论如何我们并不关心。这个序列与 Artem's answer 中的命令序列基本相同,只是没有使用可怕的管道命令。


您知道是否可以创建一个孤立分支,当您从其他“树”签出任何分支时保持可见?
@JJD:我认为你想要的是 git merge。 ( git checkout master && git merge --no-commit "orphan-branch" ) 使用 git-reset 或使用索引可以使用一些类似的技巧。但这取决于您所需的工作流程。
@Matthew 这是changelog for git 1.7.2
@phord我或多或少地认为孤儿包含与项目源代码分离的单元测试或文档等内容。
@JJD:我给的脚本应该给你你想要的,除非我误解了你。当您说“保持可见”时,您的意思是即使您签出了不同的分支,文件仍将保留在工作目录中?在 git merge 上使用 --no-commit 将实现此目的。您可能需要使用 git reset origin/master 跟进,以便您的下一次提交转到您想要的位置,但是您的孤立分支中的文件将显示为“未跟踪文件”,除非您还将它们包含在您的 .gitignore 文件中。
A
Artem Tikhomirov

Git Community Book

git symbolic-ref HEAD refs/heads/newbranch 
rm .git/index 
git clean -fdx 
<do work> 
git add your files 
git commit -m 'Initial commit'

对于现代版本的 git,下一个答案更好。
@kikito:回复:“下一个答案更好” ... SO 上的排序并不稳定。您能否添加一个指向您认为更好的答案的链接。
我指的是stackoverflow.com/a/4288660/312586。你是对的,我不应该说“下一步”。当我发表评论时,它的分数低于这个答案。
rm .git/index 很丑 :-)
这个更适用于“我想提交到分支,如果它以前不存在就创建它”的情况
J
Jakub Narębski

尽管使用 git symbolic-ref 和删除索引的解决方案有效,但创建 new 存储库可能概念上更干净

$ cd /path/to/unrelated
$ git init
[edit and add files]
$ git add .
$ git commit -m "Initial commit of unrelated"
[master (root-commit) 2a665f6] Initial commit of unrelated
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 foo

然后从中获取

$ cd /path/to/repo
$ git fetch /path/to/unrelated master:unrelated-branch
warning: no common commits
remote: Counting objects: 3, done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From /path/to/unrelated
 * [new branch]      master     -> unrelated-branch

现在您可以删除 /path/to/unrelated


在我看来,一个干净的概念会涉及到 git branchgit checkout 的选项。我很高兴 git 让这种事情成为可能,但为什么不能更容易呢?
因为它是,而且应该是一种罕见的东西。如果你有不相关的东西分支,它通常属于不相关的存储库,而不是填充到现有的存储库中(尽管有例外)。
+1。对于 git 新手,您显然可以通过 git branch 列出分支并通过 git checkout BRANCH_NAME 在它们之间切换。
谢谢你,我不会自己考虑的。这非常有用,因为它维护了其他 repo 的历史记录(如果有的话)。
u
unknownprotocol

当前选择的答案是正确的,我只是巧合地补充一下......

这实际上正是 github.com 允许用户通过一个名为 gh-pages 的孤立分支为他们的存储库创建 Github 页面的方式。这里给出并解释了漂亮的步骤:

https://help.github.com/articles/creating-project-pages-manually

基本上设置它的 git 命令如下:

git checkout --orphan gh-pages (在你的仓库中创建一个名为 gh-pages 的无父分支) git rm -rf 。 (从分支工作树中删除任何文件) rm '.gitignore'(甚至是 gitignore) 现在添加网站内容(添加 index.html 等)并提交和推送。利润。

请注意,您还可以在您的存储库中 designate a /docs folder 作为 Github 用于构建网站的“项目站点”的来源。

希望这可以帮助!


D
Daniel Reis

在最近的 Git 版本中,至少是 2.27,这可以使用 switch 命令干净地实现:

git switch --orphan <new-branch>

官方文档:https://www.git-scm.com/docs/git-switch


G
Greg Hewgill

Github 有一个名为 Project Pages 的功能,您可以在其中在项目中创建一个特定的命名分支,以提供将由 Github 提供的文件。他们的指令如下:

$ cd /path/to/fancypants
$ git symbolic-ref HEAD refs/heads/gh-pages
$ rm .git/index
$ git clean -fdx

从那里你有一个空的存储库,然后你可以添加你的新内容。


S
Sing

有时我只想立即在项目中创建空分支然后开始工作,我将执行以下命令:

git checkout --orphan unrelated.branch.name
git rm --cached -r .
echo "init unrelated branch" > README.md
git add README.md
git commit -m "init unrelated branch"

V
VonC

如果您的现有内容已经提交,您现在(Git 2.18 Q2 2018)可以将其提取到自己的新孤立分支中,因为“git rebase -i --root”的实现已更新为更多地使用序列器机制。

该定序器就是现在的allowing to transplant the whole topology of commit graph elsewhere

请参阅 Johannes Schindelin (dscho)commit 8fa6eeacommit 9c85a1ccommit ebddf39commit 21d0764commit d87d48bcommit ba97aea(2018 年 5 月 3 日)。
(由 Junio C Hamano -- gitster --commit c5aa4bc 中合并,2018 年 5 月 30 日)

sequencer:允许引入新的根提交新创建的根提交。现在可以通过在选择想要成为根提交的提交之前插入命令 reset [new root] 来实现。例子:

reset [new root]
pick 012345 a commit that is about to become a root commit
pick 234567 this commit will have the previous one as parent

这与 reset 命令的其他用途不冲突,因为 [new root] 不是(部分)有效的引用名称:在引用名称中,左括号和空格都是非法的。


S
ShawnFeatherly

创建一个单独的存储库对我来说效果很好。不必担心

在其他地方创建一个新的空仓库。将 master 分支重命名为 master 以外的任何东西,即 gh-pages 开始你的孤儿工作。将您的工作提交到新存储库中的唯一分支。将新分支推送到包含原始主分支的同一个远程仓库。

此方法在以下内容中有所提及:

https://gitlab.com/tortoisegit/tortoisegit/-/issues/1090#note_77403778

https://gist.github.com/chrisjacob/1086274/382ef1ccc22b57b9b1f0e3a362b39e806b9ba04c


B
Benoît

http://wingolog.org/archives/2008/10/14/merging-in-unrelated-git-branches 找到了这个脚本,它工作得很好!

#!/bin/bash

set -e

if test -z "$2" -o -n "$3"; then
    echo "usage: $0 REPO BRANCHNAME" >&2
    exit 1
fi

repo=$1
branch=$2

git fetch "$repo" "$branch"

head=$(git rev-parse HEAD)
fetched=$(git rev-parse FETCH_HEAD)
headref=$(git rev-parse --symbolic-full-name HEAD)

git checkout $fetched .

tree=$(git write-tree)

newhead=$(echo "merged in branch '$branch' from $repo" | git commit-tree $tree -p $head -p $fetched)
git update-ref $headref $newhead $head
git reset --hard $headref

我相信使用git fetch $REMOTE $REMOTE_BRANCH:$LOCAL_BRANCH也可以达到同样的效果。我错过了什么吗?