我越是深入研究问题,我就越能得到一个更清晰的问题摘要:如何使用git获取DAG中实际上是我的应用程序域中的树的顶点的父节点基础设施?
读得很好。任何想法都是受欢迎的(特定于git)。
我有一个存储库,其历史记录是由我通过半自动命令编写的脚本构建的:
因此,我可以根据需要自动将任何类型的信息放入历史记录中,例如,当执行命令时,那些标记为黄色的标记。
所有这一切的关键要求是,当合并冲突发生时(并且必须发生,因为脚本的目标是让用户意识到合并冲突,并与之联系其他用户为了找到问题的解决方案 - 如果发生合并冲突, 是一个问题,我希望脚本能够激发用户之间的沟通。)
现在,考虑到这一点,我们假设我想恢复合并提交。这适用于非冲突的合并,例如此图像中的install-def
。我只需要使用git revert -m 1 install-def
(例如)。
当我需要恢复install-abc
时,该过程变得更加复杂,因为我想要准确地恢复那些提交,install-abc
(合并提交)和来自remotes/hacklet/abc/master
的“灰色”子项
换句话说,要获得仅profile/myfirstprofile
和remotes/hacklet/def/master
的线性历史记录。
在半自动脚本中实现此目的的最简单,最安全的方法是什么,假设我可以使用任何标记对任何提交进行注释?最好不必做任何与 DAG 相关的事情(或者就此而言,递归),因为脚本是用bash编写的。
“revert”执行“卸载”。 git revert -m 1 ...
适用于在install-def
的情况下还原提交,但对于install-abc
,它会给出:
error: could not revert 18cff49... using hacklet/abc/master in profile
myfirstprofile hint: after resolving the conflicts, mark the corrected
paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and
commit the result with 'git commit'
注意:profile
分支可以包含许多此类install-
提交,我想只删除其中一个。 “安装”和“配置文件”都不能嵌套。
注意:我知道“模块”和“子树”。请不要理会提及它们,我在这里做的事情是特定于应用程序域(git是应用程序的一部分),这不是关于在开发周期中使用git。我已经彻底分析了这两个功能,它们根本不适合我脚本的应用程序域。
附录1
我已经破解了包含这些信息,这让我更容易理解:
如果你认为这变得过于复杂,那就不是了,它基本上是一遍又一遍的模式:
此处,只有start-profile
,install-abc
和install-foo
没有冲突。但树的结构确实看起来“相同”。
最后一个,包含所有冲突(第一个除外,install-abc
),因为我喜欢gitk的彩色输出:
还有一个,但根本没有冲突:
注意:可能会在profile/myfirstprofile
分支中标记未标记的单个提交。在这种情况下,应保留这些提交。真的没有别的东西应该“卸载”,但是那个提交属于install-THING
。
附录2
虽然我已经发现before-install-
可以找到相应的git describe --tags $(git rev-list -1 install-abc)
。但是:
根据标记install-def
,如何找到子提交 - 在最后一张图片中是before-install-ghi
?
考虑到最后的注意(中间没有标记的提交),如何找到这些“子和父”提交适合粘在一起,没有我想要的所需install-THING
卸载“?
注意:我希望每次想要“卸载”某些东西时都不必迭代树。
答案 0 :(得分:1)
我觉得这个解释很复杂,因为它没有对普通的git术语进行对冲,但据我所知,你问的是三个问题中的一个(很确定它是#3):
对于此解释,请考虑此图:
G
|
F
|\
D E
|/
C
|
B
|
A
首先,一些术语:
提交'D'和'E'是提交'F'的“合并父”,这是一个合并提交。您看到的图表几乎总是有两个父母,您的术语中的“左”和“右”,git术语中的“第一”和“第二”,但合并可能具有的父母数量没有限制。从技术上讲,所谓的“章鱼合并”是可能的,可能是三个或更多的父母。它们在实践中很少使用。
使用git中的^
语法规范地描述了合并父项。请使用此语法,因为它可以让您更轻松地理解您的问题。第一个父级是^1
,第二个父级是^2
。换句话说:
F^1 is equivalent to D
F^2 is equivalent to E
你问题中最令人困惑的方面是了解你想要达到的状态。让我们来解决三个可能的问题:
假设您尝试达到提交'D'并且不关心'E','F'或'G'引入的更改。使用Let_Me_Be的答案:
git reset --hard D
如果您想要达到'E',但根本不关心保留'D','F'或'G'引入的更改,那么同样可行。
假设您想要更复杂的东西:假设您想要在不丢失'E'或'G'的变化的情况下恢复'D'的变化。这也是一个微不足道的操作,只要'F'和'G'都不是基于'D'的变化。在那种情况下:
git revert -m 2 'F'
命令语法的意思是“恢复合并提交'F'并使第二个父级成为主线。”由此产生的历史(再次假设'G'不是基于'D')看起来好像'D'从未合并,但当然实际历史将如下所示:
H
|
G
|
F
|\
D E
|/
C
|
B
|
A
其中'H'是还原提交。如果您想恢复'F'并使用'D'作为主线,只需在命令中更改指定的父编号:git revert -m 1 'F'
(注意使用1
表示“第一个父级”。)< / p>
好。这是最棘手的情况。如果你经常这样做,git不是你的问题的解决方案,无论其背景如何。如果可以的话,Git试图保持对冲突解决的完全不可知。这就是重点:如果合并冲突可以由软件解决,它就会这样做。如果它们在您的工作流程中经常出现,那么您的工作流程就是问题,而不是您的VCS。
如果你想避免历史修订(即git rebase
,即使我们可以完全自动完成也是疯狂的),解决你的恢复冲突的唯一方法是根据'D'代码恢复后续提交。换句话说:
git revert G
git revert -m 1 F
如果你想使用'git cherry-pick G'(最初的'G'提交哈希),你可以重新申请'G',但是几率正在应用它不会顺利进行。您生成的历史记录如下所示:
J - Reapplication of G
|
I - Revert of F
|
H - Revert of G
|
G
|
F
|\
D E
|/
C
|
B
|
A
如果这个答案能够最好地描述你的情况,我强烈建议你在git以外的地方寻找你的申请。它不是为了轻松做你想做的事情而设计的,因为你正在做的事情将是一个相当破碎的版本控制工作流程。我对你的应用程序捕获所有边缘案例的能力持怀疑态度。即使冲突本身是可预测的,让它进行智能冲突解决也不是一个容易的问题。我当然可能是错的。
答案 1 :(得分:0)
这更像是一个猜测,然后是一个答案(因为我仍然对这个问题感到非常困惑)。
但我的猜测是你想要这样做:
git reset --hard start_myfirstprofile
git merge remotes/hacklet/def/master
如果要重置为合并前的状态。
git reset HEAD~1
在正确的分支上应该没问题。