用另一个提交的状态替换整个应用程序的状态

时间:2019-05-19 14:06:45

标签: git cherry-pick merge-strategy

我想做“最艰难的版本”的Cherry-Pick / Merge / Rebase / Checkout,这意味着我分支上的应用程序状态开始看起来完全像在Cherry-Picked提交中(但保留历史记录)我的分支机构)。实际上,我可以复制我的仓库,删除分支中的所有内容,然后从复制版本集中复制全部内容到所需提交。但是,这并不方便,我相信有一些更简单的方法。

我已经尝试过git cherry-pick <hash> --strategy-option theirs,但这并不完美,因为它不会删除在经过精心挑选的提交中不存在的文件,这对我来说是一个大麻烦。

那我该怎么办?

编辑:我澄清了我还需要保留我的历史记录,这首先是不明显的。

3 个答案:

答案 0 :(得分:3)

那根本不是挑樱桃。不要用git cherry-pick来做:要用git commit来做。这是一个非常简单的配方 1

$ git checkout <branch>                # get on the target branch
$ cd $(git rev-parse --show-toplevel)  # ensure you're at the top of the work-tree
$ git rm -r .                          # remove all tracked files from index and work-tree
$ git checkout <hash> -- .             # create every file anew from <hash>
$ git commit                           # make a new commit with all new info

如果您要从提交<hash>复制提交消息等,请考虑在-c <hash>行中添加git commit


1 这不是最简单的,但应该可以理解。较简单的命令在初始git checkout之后使用管道命令,例如:

git read-tree -u <hash>
git commit

或:

git merge --ff-only $(git commit-tree -p HEAD <hash>^{tree} < /tmp/commit-msg)

(未经测试,第二个则必须构造一个提交消息)。

请记住,Git存储了提交,每个提交都是所有源文件以及一些元数据的完整快照。每次提交的元数据都包括提交者的姓名和电子邮件地址;提交时间的日期和时间戳记;一条日志消息,说明为什么为什么;对于Git来说,至关重要的是提交的 parent 的哈希ID。

只要您具有某个提交的哈希ID,我们就说您指向提交。如果一个提交具有另一个提交的哈希ID,则带有哈希ID的提交将指向另一个提交。

这意味着嵌入在每个提交中的这些哈希ID构成了一个向后看的链。如果我们使用单个字母代表提交,或按顺序对它们进行编号C1C2,依此类推,则得到:

A <-B <-C <-D ... <-G <-H

或:

C1 <-C2 <-C3 ... <-C7 <-C8

每次提交的实际名称当然是一些丑陋的哈希ID,但是使用这样的字母或数字会使我们(人类)更容易处理它们。无论如何,关键是如果我们以某种方式将 last 提交的哈希ID保存在链中,那么我们最终就可以向后跟踪链的其余部分,一次提交一次

我们在Git中存储这些哈希ID的位置位于分支名称中。因此,像master这样的分支名称只存储提交H的真实哈希ID,而H本身存储其父G的哈希ID,后者存储的是{其父F,依此类推:

... <-F <-G <-H   <-- master

这些从HGF的后向链接,以及每次提交保存的快照,以及有关谁进行提交以及为什么进行提交的元数据, 您存储库中的历史记录。要保留以H结尾的历史记录,您只需要确保在进行 next 提交时,将H作为其父级:

...--F--G--H--I   <-- master

通过进行新的提交,Git更改名称master来记住新的提交I的哈希ID,其父是H,其父是(仍然){{1 }},等等。

您的目标是使用与其他提交(例如下面的G)相关的快照进行提交I

K

Git实际上是根据 index 中的内容而不是源代码树中的内容构建新的提交的。因此,我们从...--F--G--H <-- master \ J------K------L <-- somebranch 开始,将提交git checkout master设为当前提交,并将H设为当前分支,这将从提交master的内容中填充索引和工作树。

接下来,我们希望索引匹配提交H(除了K中没有其他文件之外),因此我们首先从索引中删除每个文件。为了保持理智(即让我们可以看到我们在做什么),我们让Get对工作树执行相同的操作,该工作树会自动执行。因此,在确保K指向整个索引/工作树对之后,我们运行git rm -r .,方法是确保我们位于工作树的顶部而不是某个子目录/子文件夹。

现在,只有未跟踪的文件保留在我们的工作树中。如果愿意,我们也可以使用普通的.rm删除它们,尽管在大多数情况下它们是无害的。如果您希望删除它们,请随时执行此操作。然后,我们需要从提交git clean来填充索引(工作树再一次出现),因此我们运行Kgit checkout <hash-of-K> -- .很重要:它告诉Git 不要 switch 提交,只需从此处命名的提交中提取所有内容即可。现在,我们的索引和工作树与commit匹配-- .

(如果提交K具有我们在K中拥有的 all 个文件,则可以跳过H步骤。我们只需要{{1} } 删除 git rm中但不在git rm中的文件。)

最后,现在我们有了与提交H匹配的索引(和工作树),我们可以安全地进行类似于K的新提交,但不会将连接到 K

如果要合并,请使用K

以上序列导致:

K

其中提交{{1}中的保存的源快照与提交git merge --no-commit中的完全匹配。但是,历史记录是通过读取...--F--G--H--I <-- master \ J-------K-----L <-- somebranch ,发现其指向I,然后读取提交K以及向后指向masterI和{ {1}},依此类推,绝对不要提及提交I

您可能想要的是这样的历史记录:

H

在这里,提交G会回到两者提交F K

使提交...--F--G--H--I <-- master \ / J-------K-----L <-- somebranch 成为这种变体有点棘手,因为除了使用I管道命令之外,唯一使 make 提交H的方法是使用K

在这里,简单的方法是运行I,如下所示:

git commit-tree

我们在这里使用I使事情变得更快,更流畅。我们正在构建的实际上是git merge的结果,除了没有git merge -s ours --no-commit的事实。 $ git merge -s ours --no-commit <hash> # start the merge but don't finish it $ git rm -r . # discard everything $ git checkout <hash> -- . # replace with their content $ git commit # and now finish the merge 的意思是忽略他们的提交,只保留我们提交的内容-s ours然后我们将其丢弃,并用他们提交git merge -s theirs的内容替换,然后完成合并以获得指向git merge -s theirs-s ours的合并提交H

和以前一样,有 个管道命令技巧使此操作更加容易。除非您了解Git内部使用的低级存储格式,否则它们并不是显而易见的。 “删除所有内容,然后检出不同提交内容的方法”确实很明显,而且很容易记住。

答案 1 :(得分:2)

您需要使用Q1 = Label(fenetre2, text="1) Comment se nomme le président français?", font='Helvetica 10 bold') Q1.pack() Q1A = Radiobutton(fenetre2, text="Nicolas Sarkozy", value=2, variable=rep1) Q1A.pack() Q1B = Radiobutton(fenetre2, text="Emmanuel Macron", command=ajouter1, value=1, variable=rep1) Q1B.pack() Q1C = Radiobutton(fenetre2, text="François Hollande", value= 3, variable=rep1) Q1C.pack() def ajouter1(): global score score+=1 Score = "Bravo, Votre score est de: " + str(score) + "/10" var_label.set(Score) Score = Label(fenetre3, textvariable=var_label, font='Helvetica 10 bold') var_label.set("Bravo, Votre score est de: 0/10") Score.pack() 。首先,合并...策略或结果无关紧要。如果有冲突,没关系...添加所有文件并保存(不用担心...我们将在一秒钟内修改正确的内容)。

现在,签出您要从中获取内容的修订。如果是分支,请使用git reset --soft。现在,--detach到原始分支(我​​们之前进行过合并的位置)。

现在完成技巧的运行git reset --soft,您就完成了。如果您喜欢结果,请使用git commit --amend --no-edit移动原始分支的分支指针,然后完成。

原始收据,但不保存其他分支的历史记录 您要做的是git branch -f the-original-branch。检出您希望另一个分支看起来像(内容方面)的修订版(或带有--detach的分支)。然后执行git reset --soft。这样会将分支 pointer 设置为此版本或分支,工作树将类似于我们之前检出的树,并且它们之间的所有差异都将在索引上。现在,当您提交时,您将获得一个修订版本,该分支的外观将与您首先签出的原始版本相似。...如果您喜欢最终结果,请移动分支指针并将其签出。

答案 2 :(得分:0)

$ git checkout --orphan new-branch-name
$ git cherry-pick <hash>