我相信做你想做的最好的方法是在特定于机器的分支上进行提交,然后使用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
这会将新创建的提交对象的 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 应用它。
-
git apply --cached 使用 --cached 选项,这会将补丁直接应用于索引中的版本,而无需触及工作树。因此,您可以创建一个差异,读取另一个分支的树,将其应用于索引,提交树,然后您就设置好了。这可能是最棒的方法了。
这一切如此困难的原因是,所有让您访问其所有强大合并功能的 git 命令都依赖于工作树中的文件。当您考虑它时,您正在尝试执行的任务是合并 - 您在一个分支上有一个差异,并且您想将它应用到另一个分支上。获得结果的方法是进行三路合并,使用原始分支上的差异、与另一个分支的共同祖先以及另一个分支的尖端。如果没有检出其他分支,您将无法真正进行此合并!
像往常一样使用管道命令执行操作时,您应该非常小心地了解一切是如何工作的,以免严重破坏您的存储库。也就是说,在重组现有存储库(由其他人创建的存储库......不要问)时,我实际上已经使用它来发挥很大的作用。我只是在这些情况下重新安排提交 - 使用读取树而不是通常更新索引 - 所以它比你可能尝试做的要简单得多。
替代方法
说了这么多,您还可以采取其他几种方法来完成您想做的事情。
克隆您的存储库。如果您只跟踪配置文件,这不会占用太多额外空间,而且事情会容易得多。如果你真的很着迷,你甚至可以使用git new-workdir(链接到 git.git 的 HEAD 中的版本)脚本只创建一个工作目录,而不复制其余的 repo(它使用 .git 中的符号链接目录)。请记住要小心将一个 workdir 提交到另一个已签出的分支 - 另一个最终会导致其工作树不同步。
-
编写一个单一提交包装脚本 - 这是对所有这些选项的另一个分支进行单一提交最接近的方法:
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^