如何让git push永久跳过来自详细分支的提交?

如何让git push永久跳过来自详细分支的提交?,git,git-branch,git-push,Git,Git Branch,Git Push,对于一次回购,我使用一个简单的脚本定期提交对文件的更改,以保留一个非常详细的非逻辑历史记录,这是我出于统计目的想要保留的(例如,我知道关于git-rebase,但我无论如何都想保留这个非逻辑历史记录)。目前,我正在提交一个单独的分支autocommit并使用它 git checkout master git merge --squash autocommit git commit git checkout autocommit git merge --ff-only master 对于“正确”

对于一次回购,我使用一个简单的脚本定期提交对文件的更改,以保留一个非常详细的非逻辑历史记录,这是我出于统计目的想要保留的(例如,我知道关于
git-rebase
,但我无论如何都想保留这个非逻辑历史记录)。目前,我正在提交一个单独的分支
autocommit
并使用它

git checkout master
git merge --squash autocommit
git commit
git checkout autocommit
git merge --ff-only master
对于“正确”,承诺保持
主分支整洁,同时保持与
自动提交分支的关系。所以我有这样的历史

| *   95e4189 Merge branch 'main' into autocommit
| |\
| |/
|/|
* | 040386a <= created via git merge --squash autocommit
| * 72bc5a5 autocommit
| * 9aaf5a6 autocommit
| * ea758c0 autocommit
| * 7ff1de8 autocommit
其中
↓'
表示一个
git merge--squash
,这意味着
A3
不是
M2
的父级,但只有
M1
是,而
A3'
只是合并回
M2
,以便更好地跟踪连接。我想我想要的只是

M1--------------=> M2 ---> ....                             [master]
  \            /
  A1 -> A2 -> A3 -> A4 (or maybe A3' first merging M2 back) [autocommit]

但是,
autocommit
分支中的
A1
等提交都没有被推送。

要了解可能的情况,了解一下git的工作原理是很有用的。从根本上说,git构建了分层的版本控制模型:

  • 一种内容寻址数据库,在该数据库中,可以根据数据内容的散列查找任意数据块。这些blob是不可变的,因为更改任何内容都会导致新的散列,因此永远不会更新现有项
  • 一种有向无环图,其中blob描述存储库的状态、一些元数据(日期、提交者、消息等)以及零个或多个父级。父项由它们的不可变散列寻址,而父项又是为新提交而散列的内容的一部分
  • 指向特定提交的指针,以给它们提供更为用户友好的名称。我们称其中一些为“分支”,但它们只指向一个提交;从那里,git可以沿着父引用向后走,以找到“在”该分支上的所有提交
  • 从这里,我们可以看到一些不可能的事情:

    • 让您的本地副本记录一次提交的两个父项,但github只显示同一次提交的一个父项-不同的父项集将给出不同的哈希值,因此没有人会将其识别为同一次提交
    • 记录了两个父级,但没有在
      自动提交
      分支上推送提交-git不知道它在历史记录中找到的合并中的分支名称,它只是将所有父级提交视为它向后跟踪的历史记录的一部分
    • 推送可在一个分支上访问的所有提交,但也可在另一个分支上访问的提交除外。这仍然不是一个足够强的定义,因为最终您将在创建
      autocommit
      分支之前到达历史记录中的提交,git也不知道在历史记录中发生了什么
    • 即使您可以定义不希望推送的提交列表,工具也不会很高兴找到一个显然不存在的对父提交的引用,并且可能会假设您的存储库已损坏
    我真的只能想到两个选择:

    • 从您的自动提交分支记录一个正常的合并,并在历史记录中显示自动提交
    • 像现在一样挤压提交,但是创建自己的工具来记录挤压的自动提交,并允许您查找它们,确保没有遗漏任何内容,等等
    涵盖了大多数可能性,但还有一种可能性,前提是您的“详细”和“非详细”分支始终在“更新非详细分支”点完全同步源代码,即:

    o----------A----------B   <-- master
     \         ⋮\         ⋮\
      D1--D2--D3-M1--D4--D5-M2   <-- detailed
    
    由于没有从
    o
    o
    的更改(
    o
    是此合并的合并基础),Git将这些更改与
    详细的
    上的
    o
    之后的更改“组合”。产生的非合并(挤压)提交是提交
    A
    。但在提交
    A
    后,我们立即运行:

    git checkout detailed
    git merge master
    
    Git现在比较commit
    o
    vs
    A
    来查看它们的变化,并比较
    o
    vs
    D3
    来查看我们的变化。这些更改完全匹配(当然),因此merge commit
    M1
    有一个快照,该快照同时匹配提交
    D3
    a

    我们现在在
    detailed
    上进行更多的常规详细提交,然后重复上述过程来创建提交
    B
    M2
    。这次的合并基础是提交
    A
    。最终结果是,我们与提交
    A
    时处于相同的位置,但下一次执行所有这些操作时,合并基础将是提交
    B

    请注意,可以创建提交
    A
    B
    ,而无需运行
    git merge--squash
    ,无需运行
    git merge
    ,就可以创建合并
    M1
    M2
    :我们知道每次提交所需的树,因此可以简单地使用
    git commit tree
    进行这些提交。但是
    git commit tree
    不是面向用户的命令,使用起来有点困难。您可以编写自己的Git命令来执行此操作,以确保所有操作都正确完成,例如,没有直接提交到
    master
    ,但是如果您使用
    Git merge--squash,直接提交到
    master
    实际上就可以了。下面是其中一个可能的样子,表示为哈希ID为
    C
    的提交:

    o----------A----------B-----C----D   <-- master
     \         ⋮\         ⋮\         ⋮\
      D1--D2--D3-M1--D4--D5-M2--D6--D7-M3   <-- detailed
    

    o----A----B----C----D谢谢你的输入,我几乎担心你是对的……不确定我是否理解正确,但这不是我已经在使用的
    git merge--squash
    策略吗?也许我遗漏了一个细节嗯,不,我认为你是对的,那是你已经在做的。
    git checkout detailed
    git merge master
    
    o----------A----------B-----C----D   <-- master
     \         ⋮\         ⋮\         ⋮\
      D1--D2--D3-M1--D4--D5-M2--D6--D7-M3   <-- detailed