为了账号安全,请及时绑定邮箱和手机立即绑定

将git父指针设置为其他父级

/ 猿问

将git父指针设置为其他父级

Git
拉莫斯之舞 2019-09-18 15:16:41

如果我在过去提交指向一个父级的提交,但我想更改它指向的父级,我将如何进行此操作?


查看完整描述

3 回答

?
慕沐林林

用git rebase。它是Git中的通用“take commit(s)and plop it / them on a different parent(base)”命令。


但是要注意一些事情:


由于提交SHA涉及其父项,因此当您更改给定提交的父项时,其SHA将更改 - 在开发行中将更改其后的所有提交(比它更新)的SHA也将更改。


如果您正在与其他人合作,并且您已经将提交的问题公开推送到他们撤回的地方,那么修改提交可能是一个坏主意™。这是由于#1,因此在尝试弄清楚由于您的SHA不再与“相同”提交相匹配时发生的事情时,其他用户的存储库将会遇到混淆。(有关详细信息,请参阅链接手册页中的“从上游重新恢复”部分。)


也就是说,如果你目前在一个分支上有一些你希望转移到新父级的提交,它看起来像这样:


git rebase --onto <new-parent> <old-parent>

这会将当前分支之后 <old-parent>的所有内容移动到顶部<new-parent>。


查看完整回答
反对 回复 2019-09-18
?
慕田峪9158850

如果事实证明你需要避免重新定义后续提交(例如,因为历史重写是站不住脚的),那么你可以使用git替换(在Git 1.6.5及更高版本中可用)。


# …---o---A---o---o---…

#

# …---o---B---b---b---…

#

# We want to transplant B to be "on top of" A.

# The tree of descendants from B (and A) can be arbitrarily complex.


replace_first_parent() {

    old_parent=$(git rev-parse --verify "${1}^1") || return 1

    new_parent=$(git rev-parse --verify "${2}^0") || return 2

    new_commit=$(

      git cat-file commit "$1" |

      sed -e '1,/^$/s/^parent '"$old_parent"'$/parent '"$new_parent"'/' |

      git hash-object -t commit -w --stdin

    ) || return 3

    git replace "$1" "$new_commit"

}

replace_first_parent B A


# …---o---A---o---o---…

#          \

#           C---b---b---…

#

# C is the replacement for B.

在建立了上述替换后,对对象B的任何请求都将实际返回对象C.除了第一个父项(相同的父项(第一个除外),同一个树之外,C的内容与B的内容完全相同)相同的提交消息)。


默认情况下,替换处于活动状态,但可以通过使用git--no-replace-objects选项(在命令名之前)或通过设置环境变量来启用替换。可以通过推送(除正常之外)共享替换。GIT_NO_REPLACE_OBJECTSrefs/replace/*refs/heads/*


如果您不喜欢commit-munging(使用上面的sed完成),那么您可以使用更高级别的命令创建替换提交:


git checkout B~0

git reset --soft A

git commit -C B

git replace B HEAD

git checkout -

最大的区别在于,如果B是合并提交,则此序列不会传播其他父项。


查看完整回答
反对 回复 2019-09-18
?
HUWWW

请注意,更改Git中的提交要求必须更改其后的所有提交。如果您已经发布了这部分历史记录,那么就不鼓励这样做了,有人可能会在变更前的历史上建立自己的工作。


替代解决方案git rebase中提到琥珀的反应是使用移植机制(见Git中移植的定义Git的词汇和文档.git/info/grafts文件在Git仓库布局文档)改变提交父,检查它做正确的事情与一些浏览器的历史(gitk,git log --graph等等,然后使用git filter-branch(如其联机帮助页的“示例”部分所述)使其永久化(然后删除移植物,并选择删除备份git filter-branch或重新定义存储库的原始引用):


echo“$ commit-id $ graft-id”>> .git / info / grafts

git filter-branch $ graft-id..HEAD

注意 !!!该解决方案是从底垫的解决方案不同的是git rebase将重订/移植的变化,而移植物为基础的解决方案只会重新设置父级提交原样,完全没有考虑到老上级和新的父之间的差异!


查看完整回答
反对 回复 2019-09-18
  • 3 回答
  • 0 关注
  • 180 浏览
我要回答

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信