在git中,有没有简单的方法将无关分支引入存储库?


328

今天在帮助有git问题的朋友时,我不得不介绍一个需要与该master分支完全分开的分支。该分支的内容确实与该分支上开发的内容有不同的来源master,但是master稍后将合并到分支中。

我从头到尾地阅读了约翰·威格利的《Git》,从中回忆起分支实际上是遵循某种约定的提交的标签,以及如何将提交与文件树以及父提交(或可选地)绑定在一起。我们使用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的人喜欢的那种过程。有没有更简单的方法来创建一个新分支,该分支与到目前为止存储库中发生的一切完全无关?

Answers:


510

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

git checkout现在支持该--orphan选项。从手册页

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

创建一个新的孤立分支,名为<new_branch>,从<start_point>开始并切换到该分支。在这个新分支上进行的第一次提交将没有父母,这将是与所有其他分支和提交完全脱节的新历史的根源。

这并不能完全满足要求者的要求,因为它从中填充了索引和工作树<start_point>(因为毕竟这是一个checkout命令)。唯一需要执行的其他操作是从工作树和索引中删除所有不需要的项目。不幸的是,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的答案中的命令序列实质上具有相同的作用,只是不求助于可怕的管道命令。


您是否知道可以创建一个孤立分支,当您从另一个“树”中签出任何分支时仍保持可见?
JJD 2011年

1
@JJD:我想您想要的是git merge。 ( git checkout master && git merge --no-commit "orphan-branch" ) 一些类似的技巧可以使用git-reset或使用索引来工作。但这取决于您所需的工作流程。
2011年

@Matthew这是git 1.7.2的变更日志
JJD 2011年

@phord我或多或少地认为孤立对象包含与项目源代码分开的单元测试或文档之类的东西。
JJD 2011年

2
@JJD:我给的剧本应该给你你想要的东西,除非我误解了你。当您说“保持可见”时,是否意味着即使您签出了另一个分支,文件仍将保留在工作目录中?使用--no-commiton git merge将实现此目的。您可能需要跟一个,git reset origin/master以便您的下一次提交到达您想要的位置,但是孤立分支中的文件将显示为“未跟踪的文件”,除非您也将它们包括在.gitignore文件中。
2011年

32

来自Git社区书

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

1
对于现代版本的git,下一个答案更好。
kikito 2012年

14
@kikito:回复:“下一个答案更好”……在SO上的排序不稳定。您能否添加指向您认为更好的答案的链接。
David J.

2
我指的是stackoverflow.com/a/4288660/312586。您是对的,我不应该说“下一个”。当我发表评论时,它的得分低于此答案。
kikito 2014年

1
rm .git/index是丑陋的:-)
西罗·桑蒂利

此选项在“我想提交到分支,如果以前不存在的情况下创建它”的情况下更好地工作
max630 2015年

22

尽管带有git symbolic-ref索引并删除索引的解决方案有效,但是从概念上讲,创建存储库可能更干净

$ 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 branch或的选项git checkout。我很高兴git使这种事情成为可能,但是为什么不更容易呢?
丘卢

3
因为它是,应该是一件罕见的事情。如果您有不相关的事物分支,它通常属于不相关的存储库,而不是将其填充到现有存储库中(尽管有例外)。
JakubNarębski09年

1
+1。对于其他git新手,您显然可以通过以下方式列出分支git branch之间进行切换git checkout BRANCH_NAME
akavel 2011年

谢谢你,我不会自己考虑的。这特别有用,因为它可以维护其他存储库的历史记录(如果有的话)。
BM5k 2012年

13

Github具有一项称为“ 项目页面”的功能,您可以在项目中创建一个特定的命名分支以提供将由Github服务的文件。他们的指令如下:

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

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


10

当前选择的答案是正确的,我将恰好添加...

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

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

基本上,使用git命令进行设置如下:

  1. git checkout --orphan gh-pages (在您的仓库中创建一个名为gh-pages的无父母分支)
  2. git rm -rf . (从分支工作树中删除所有文件)
  3. rm '.gitignore' (甚至是gitignore)
  4. 现在添加网站内容(添加index.html等),然后提交并推送。
  5. 利润。

请注意,您也可以指定/ docs文件夹在回购中作为Github用于构建网站的“项目站点”的来源。

希望这可以帮助!


3

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

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"

1

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

该定序器现在允许将提交图的整个拓扑移植到其他位置

请参阅Johannes Schindelin()的提交8fa6eea提交9c85a1c提交ebddf39提交21d0764提交d87d48b提交ba97aea(2018年5月3日(由Junio C Hamano合并--commit c5aa4bc中,2018年5月30日)dscho
gitster

音序器:允许引入新的根提交

--rebase-merges专为允许自由更改现有分支拓扑而​​专门设计的新模式的上下文中,用户可能希望将提交提取到以新创建的根提交开始的完全新鲜的分支中

现在可以通过reset [new root]pick想要成为根提交的提交之前 插入命令来实现。例:

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]它不是有效的引用名称(的一部分):引用名称中的左括号和空格都是非法的。


0

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

1
我相信使用可以达到相同的效果git fetch $REMOTE $REMOTE_BRANCH:$LOCAL_BRANCH。我想念什么吗?
丘卢
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.