承诺没有签出的分支机构

时间:2010-03-20 00:24:17

标签: git

我正在使用git在几台不同的机器上对我的主目录进行版本控制。我希望他们每个人都使用不同的分支,并从公共分支拉出。因此,除非提交特定于该机器的某些内容,否则应该对该公共分支进行大多数提交,在这种情况下,提交应该转到签出的,特定于机器的分支。在这种情况下,切换分支显然不是一个很好的选择。

this post中提到我想做的事情是不可能的,但我发现答案是相当直率的,也许没有考虑使用管道命令的可能性。不幸的是,我没有足够的声誉来评论该主题。我宁愿怀疑有一些方法可以做到这一点,我希望通过向你问好人来节省一小时或几小时的答案。

那么可以在不先检查分支的情况下提交到不同的分支吗?理想情况下,我想以与git commit通常相同的方式使用索引。

3 个答案:

答案 0 :(得分:12)

我认为,做你想做的最好的方法是让你的提交在特定于机器的分支之上,然后用git rebase移动它们。这与我自己的主目录大致相同 - 基本上和你的主目录一样。

# make a new branch starting from branch machine_1
git checkout -b move_to_master      
# make whatever commits you need to
git rebase --onto master machine_1 move_to_master
git checkout master
git merge move_to_master  # this is a fast-forward
git checkout machine_1
git merge master

如果您在创建move_to_master之前意外提交了machine_1,只需创建move_to_master,然后将machine_1重置回其所属的位置,并按照其余步骤操作。

然而,你的问题值得回答,我在底部提供了更多的选择。

不在当前分支上创建提交

预防措施:非常小心!这是可怕的东西!

可能提交到未使用管道命令检出的分支,只是不是非常需要。你必须让你的索引进入你想要的状态(这可能很棘手),然后你可以使用git commit-tree

git commit-tree -p $PARENT_COMMIT < $COMMIT_MESSAGE_FILE

这将打印到stdout新创建的提交对象的SHA1;假设PARENT_COMMIT是分支提示,则必须使用git update-ref更新分支到它:

git update-ref -m "commit: [commit subject]" $BRANCH $NEW_SHA1

如果您正在编写此脚本,则可以在单行中实现git update-ref -m ... $(git commit tree ...)。这是最可怕的一步。如果你将你的其他分支更新到你错误的地方,那就太糟糕了。您仍然可以找出将其重置为git reflog show $BRANCH的位置。

无论如何,这只是一个简单的部分。真正困难的是让索引进入你想要的状态而不实际检查文件。您可能使用的两个常用命令:

  • git read-tree - 将树信息读入索引,但根本不更新工作树(git checkout大致等同于git read-tree,git checkout-index和git update-ref HEAD) 。您可以使用它来使索引包含该未签出分支的内容,而不是HEAD。
  • git update-index - 修改索引。您可以使用它来从工作树中添加,删除或刷新索引中的文件。
  • git checkout-index - 将索引中的给定路径复制到工作树中。使用read-tree之后,您可以使用它来获取要更改的单个文件,对其进行修改,然后使用update-index将其重新放入。 “修改它”步骤可能很复杂 - 例如,在完成所有这些之前,您可以使用git diff创建一个补丁,然后将其应用于git apply here。
  • git apply --cached使用--cached选项,这会将修补程序直接应用于索引中的版本,而不会触及工作树。因此,您可以创建另一个分支的diff,read-tree,将其应用于索引,commit-tree,然后进行设置。这可能是最棒的方法。

这一切都非常困难的原因是,所有允许您访问其所有强大合并功能的git命令都依赖于工作树中的文件。当你考虑它时,你要做的任务是合并 - 你在一个分支上有一个差异,你想在另一个分支上应用它。获得结果的方法是进行三向合并,使用原始分支上的diff,与另一个分支的共同祖先,以及另一个分支的尖端。如果没有签出其他分支,你就无法真正做到这一点!

与使用管道命令一样,你应该非常小心地理解一切是如何工作的,这样你就不会破坏你的存储库。也就是说,我实际上在重组现有存储库时使用了这个效果(由其他人创建的存储库......不要问)。我只是在这些情况下重新安排提交 - 使用read-tree而不是通常更新-index-因此它比你可能尝试做的要简单得多。

替代方法

说完这一切后,你可以采取其他几种方法来完成你想要的工作。

  • 克隆您的存储库。如果你只是跟踪配置文件,这不会占用额外的空间,事情会变得更加容易。如果你真的很痴迷,你甚至可以使用git new-workdir(链接到git.git的HEAD中的版本)脚本只创建一个工作目录,而不是复制其余的repo(它使用符号链接.git目录)。请记住要小心将一个workdir提交到另一个work -ir中检出的分支 - 另一个最终会使其工作树不同步。

  • 编写单一提交包装器脚本 - 这是对所有这些选项的另一个分支进行单一提交的最接近的事情:

    git commit
    orig_branch=$(git symbolic-ref HEAD)
    orig_branch=${orig_branch#refs/heads/}
    git checkout master
    git cherry-pick $orig_branch
    git checkout $orig_branch
    git reset --hard HEAD^
    

答案 1 :(得分:1)

我为Visual Git Reference项目执行此操作。我运行make gh-pages,它构建网站并将其提交到gh-pages分支,而不必切换分支。请参阅我的GitHub repo,尤其是文件 Makefile 发布。我可能应该使用$GIT_INDEX_FILE作为上面提到的Chris Johnsen,但这似乎工作正常。

答案 2 :(得分:0)

我可能误解了您的请求,但请告诉我这是否是您要找的。

您从机器特定的分支开始。您进行更改,但是您希望将更改提交到公共分支,而不是提交到特定于计算机的分支。你应该做的是

git stash              # save your changes for later
git checkout common    # switch to the common branch
git stash apply        # recall the stashed changes
git commit             # commit as appropriate (on the common branch)
git stash drop         # kill off the last stashed changes (this is optional)
git checkout machine1  # go to your machine-specific branch
git rebase common      # put your machine-specific changes after the common ones
git checkout machine2  # [repeat]
git rebase common

或者,如果您的更改不适用,则可以使用git merge代替git rebase

这是否适用于您的情况?