Git - 回滚时如何从未来的提交中获取新文件

Git - how to get a new file from a future commit when rolling back

我有一个 git 分支,上面有正常的 Git 提交历史;在整个开发周期中有 additions/modifications/deletions。

我想回滚到以前的提交,但保留当前提交的文件,该文件不在我要回滚到的提交中(或者翻转它,从未来检出文件当前提交中不存在的提交)。

例如:

--------A--------B--------- ...
                 + myFile.txt;

 $ git checkout #A

我想签出提交 #A,但保留在提交 #B.

中添加的 myFile.txt

将文件 myFile.txt 复制到 git 存储库之外的某处,然后签出 A。将文件复制回存储库中。

记下您当前的提交 SHA。您可以使用 git show 在该 SHA 处获取文件的状态并在回滚后重现它。

git show abcd1234:path/to/file > path/to/file

这对于随时查看任何提交中的任何文件都很方便,并且在回滚的情况下也有效,因为 Git 暂时不会对该提交进行垃圾收集,即使它不是在您的任何分支机构上更长。你至少要等到它从你的 reflog 中消失,我相信 Git 默认情况下会保留 30 天。

您可以使用 git checkout 来执行此操作,它将路径作为可选参数:

git checkout <commit> <path>

假设您当前正处于哈希 B 的提交中,并且您想要使用提交 A 中的状态重置 goodFile.txt 之外的所有文件。

git checkout A 检查您想要从中获取大部分文件的提交

git checkout B goodFile.txt 现在从提交 B

中检出特定的好文件

git commit goodFile.txt 提交。

您现在将有一个新的提交,其中 A 作为其父项,其中包含来自 A 的所有文件和来自 BgoodFile.txt 的所有文件

虽然有一些方法可以在回滚时获取您想要维护的单个文件,但可以很容易地想象出更复杂的场景,这些场景很快就会变得笨拙。

这里的主要问题是 A 是否是您要创建的新分支(作为 B 的修改版本)。如果是,那么你不必担心 "rewriting history"(因为一切都是新的),并且有一个非常愉快的选择来管理这个和更复杂的场景:git rebase。

这是您创建 分支 A 的工作流,它基于 B,但有修改:

git checkout B          # Go to the tip of branch B.
git checkout -b A       # Create & checkout a new branch here named A.
git rebase -i           # Launch interactive rebase

此时,您将进入一个编辑器,其中列出了 B 分支的所有提交(尽管我们现在在 A 中,是 B 中更改的副本)。帮助文本非常好,但简短的总结是您现在可以重新排序提交(通过重新排序它们对应的行)、删除提交(通过删除它们对应的行)、一起压缩提交(将 'pick' 更改为 'squash'),编辑提交信息,等等。

对于您的情况,只需删除所有包含您想要丢弃的提交的行,并留下您想要保留的提交。当您对修改后的提交序列感到满意时,保存并退出文件,Git 将会消失,您将留下一个新的分支 A,它是原始分支 B 的修改形式。

Git rebase -i 是一个非常容易养成习惯的超级大国,但请注意,您永远不应该对其他人曾经见过(或已被推到上游)的现有分支进行变基。有空的时候再读一读 'git rebase',因为它是一项 Git 技能,你肯定会想要放在你的工具箱里。