压缩Git中的前两个提交?[duplicate]

hkmswyz6  于 2023-01-01  发布在  Git
关注(0)|答案(9)|浏览(127)
    • 此问题在此处已有答案**:

Combine the first two commits of a Git repository?(8个答案)
八年前就关门了。
使用git rebase --interactive <commit>,您可以将任意数量的提交压缩到一个提交中。
这一切都很好,除非你想把提交压缩到初始提交中,这似乎是不可能做到的。
有什么办法可以实现吗?

中度相关:

在一个相关的问题中,我设法提出了一种不同的方法来满足挤压第一次提交的需要,也就是说,使其成为第二次提交。
如果您感兴趣:git: how to insert a commit as the first, shifting all the others?

sxpgvts3

sxpgvts31#

2012年7月更新(git 1.7.12+)
现在你可以将所有提交重定基到root,并选择第二个提交Y与第一个提交X一起压缩。

git rebase -i --root master

pick sha1 X
squash sha1 Y
pick sha1 Z
git rebase [-i] --root $tip

这个命令现在可以用来重写从"$tip"到根提交的所有历史记录。
参见Chris Webb ( arachsys )中的commit df5df20c13 (rebase -i: support --root without --onto, 2012-06-26) on GitHub
正如评论中提到的,如果您需要在远程存储库中发布返工,那么在任何rebase操作之后都需要git push --force-with-leaseMikko Mantalainen提醒我们,它比--force更安全)。
原始答复(2009年2月)
我相信你会在SO问题"How do I combine the first two commits of a git repository?"中找到不同的食谱
Charles Bailey提供了最详细的答案,提醒我们提交是一个完整的树(不仅仅是与先前状态的差异)。
这里旧提交("初始提交")和新提交(压缩的结果)没有共同的祖先。
这意味着您不能将初始提交"commit --amend"到新的初始提交中,然后在新的初始提交上重新设置先前初始提交的历史(大量冲突)
(That使用git rebase -i --root <aBranch>时,最后一句不再正确)
相反(A是原始的"初始提交",而B是后续提交,需要将其压缩到初始提交中):
1.返回到最后一个我们想要形成初始提交的提交(detach HEAD):

git checkout <sha1_for_B>

1.将分支指针重置为初始提交,但保持索引和工作树不变:

git reset --soft <sha1_for_A>

1.使用"B"中的树修改初始树:

git commit --amend

1.临时标记这个新的初始提交(或者你可以手动记住新的提交sha1):

git tag tmp

1.返回到原始分支(假设本例为master):

git checkout master

1.在新的初始提交上重放B之后的所有提交:

git rebase --onto tmp <sha1_for_B>

1.删除临时标记:

git tag -d tmp

这样,"rebase --onto"不会在合并过程中引入冲突,因为它会将最后一次提交(B)之后的历史记录重定为tmp(表示压缩后的新初始提交):仅仅是简单的快进合并。
这适用于"A-B",但也适用于"A-...-...-...-B"(任何数量的提交都可以通过这种方式压缩到初始提交中)

6pp0gazn

6pp0gazn2#

我修改了VonC的脚本,让它自动执行所有的操作,而不需要我做任何事情。你给予它两个提交SHA1,它会把它们之间的所有内容压缩到一个名为“squashed history”的提交中:

#!/bin/sh
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout $2

# reset the branch pointer to the initial commit (= $1),
# but leaving the index and working tree intact.
git reset --soft $1

# amend the initial tree using the tree from $2
git commit --amend -m "squashed history"

# remember the new commit sha1
TARGET=`git rev-list HEAD --max-count=1`

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after $2 onto the new initial commit
git rebase --onto $TARGET $2
nkoocmlb

nkoocmlb3#

如果你只是想把所有的提交压缩到一个初始提交中,只需重置仓库并修改第一次提交即可:

git reset hash-of-first-commit
git add -A
git commit --amend

Git reset会保持工作树的完整性,所以所有的东西都在那里。所以只需要使用git add命令添加文件,然后用这些修改修改第一次提交的内容。与rebase -i相比,你会失去合并git注解的能力。

l2osamch

l2osamch4#

为了避免这个问题,我总是创建一个“no-op”的第一次提交,其中存储库中唯一的东西是一个空的.gitignore:
https://github.com/DarwinAwardWinner/git-custom-commands/blob/master/bin/git-myinit
这样,就没有任何理由去扰乱第一次提交。

vx6bjr1n

vx6bjr1n5#

这会将第二个提交挤压到第一个提交中:
第一个月

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = <sha1ofA> ];
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi
' HEAD

AB的提交消息将从B获取(尽管我更喜欢从A获取)。
与Uwe Kleine-König的答案有相同的效果,但对非首字母A也有效。

kzmpq1sx

kzmpq1sx6#

压缩第一次和第二次提交会导致第一次提交被重写。如果你有多个分支是基于第一次提交的,你应该切断那个分支。
请看下面的例子:

a---b---HEAD
 \
  \
   '---d

将a和b压缩到一个新的提交"ab"中会导致两个不同的树,这在大多数情况下是不可取的,因为git-mergegit-rebase将不再在两个分支上工作。

ab---HEAD

a---d

如果你真的想这么做,那是可以做到的。看看git-filter-branch,它是一个强大的(也是危险的)历史重写工具。

ep6jt1vc

ep6jt1vc7#

你可以使用git filter-branch来实现。

git filter-branch --parent-filter \
'if test $GIT_COMMIT != <sha1ofB>; then cat; fi'

这导致AB-C丢弃A的提交日志。

inkz8wg9

inkz8wg98#

您可以使用rebase interactive来修改最后两个提交,然后再将它们推送到远程

git rebase HEAD^^ -i
mpbci0fu

mpbci0fu9#

有一种更简单的方法可以做到这一点。让我们假设您在master分支上
创建一个新的孤立分支,它将删除所有提交历史记录:

$ git checkout --orphan new_branch

添加初始提交消息:

$ git commit -a

删除旧的未合并master分支:

$ git branch -D master

将当前分支new_branch重命名为master

$ git branch -m master

相关问题