使用git reset --soft,标记提交,以便以后可以将*压缩*

时间:2016-11-07 21:44:40

标签: git git-reset

希望压缩提交,以便面向公众的项目没有无意义的提交消息,例如" temp"或" temp123"。

我正在寻找一种方法来使用git reset --soft HEAD~5,但我不想随机选择数字5,而是想回到Git日志并找到所有与模式不匹配的提交,并且我点击了停止的模式。所以,让我们说git log提交消息如下:

temp123
fooGit
temp
fml
temp24
tmp69
tttoday
publish/release:xyz

所以我会压制前7个最近的提交,但是留下所有内容"低于" publish/release:xyz

由于相当复杂的原因,从面向公众的分支机构发出的git merge --squash对我来说不起作用,因为我最终在私有分支机构的项目中删除或重命名文件,所以有合并冲突太多了。在尝试了几种方法之后,我觉得最好用-f推向面向公众的分支,而不用担心这种冲突。

我认为在我的情况下更好的方法是像这样压缩提交:

# on private "dev" branch
# make a bunch of changes, rename files, yadda yadda
git add . && git add -A && git commit -am "temp" &&
git checkout -b squash_branch  # we do squashing on this branch to be safer
git reset --soft head~15 # apparently this undoes commits for the last 15 commits
git commit -am "A serious commit message"
git push -u public master -f  # overwrite public master
通过这种方式,我永远不必解决面向公众的分支和私有开发分支之间的冲突,这可能是超级无意义的,并且从我的经验中感到烦恼。

然而,我试图解决的问题与上面的数字15有关。我只是猜测有多少提交到#34;壁球"。我宁愿知道压扁的确切数字。

也许我可以对所有没有符合某种模式的Git提交消息的提交进行压缩?因此,当我运行壁球时,我创建一个具有特定模式的提交消息,让我们说它" XYZ"。我可以运行git reset --soft HEAD~(some git commit pattern matching to find the count)吗?

还有一个问题。在git reset --soft上进行压缩(squash_branch)之后,我应该将该分支合并回私有dev分支吗?

2 个答案:

答案 0 :(得分:2)

可以找到计数,但这有点危险,因为如果链中存在合并提交,它将是错误的数字(此处未说明):

git rev-list --count HEAD^{/publish/release:xyz}..HEAD

符号rev^{/text}表示"从给定的rev开始,搜索给定文本&的每个提交消息(la git log --grep) #34 ;.因此,第一个表达式在其提交消息中与提交publish/release:xyz匹配。然后,..语法使用该提交的ID来删除提交和早先从名称HEAD选择的提交集中提交。然后--count给出了剩余提交的计数。因此,如果您的图表如下所示:

...--o--*--o--o--o--o   <-- HEAD

其中*是其中包含文本的提交,这会丢弃提交*以及其他进一步提交,留下最后的四个o提交HEAD指向的节点。 --count然后计算这四个提交并打印4

总的来说,这是一个糟糕的策略。通过使用分支或标记名称标记点来开始更好。分支或标记名称通过指向它来标识提交。而不是试图通过模式找到提交*,只需在制作它时标记它:

git tag xyz

现在你有了这个:

     tag:xyz
        |
        v
...--o--*--o--o--o   <-- HEAD -> dev

xyz..HEAD为您提供正确的提交,您可以git reset --soft xyz使分支标签dev指回提交*

     tag:xyz
        |
        v
...--o--*   <-- HEAD -> dev
         \
          o--o--o   [only findable via reflogs]

完成此操作后,只需删除标记。

(同样,您可以使用分支或标记名称;使用您喜欢的名称;我用标签说明了这一点,因为标签名称不是假设要移动,分支名称​​执行移动。实际上,只要您git checkout分支然后进行提交或使用git reset,它们就会自动 。标记名称指向一个特定的提交,并留在那里。)

请注意,您可以在创建标记时使用搜索表示法:

git tag xyz HEAD^{/publish/release:xyz}

也就是说,在创建标记名称时,您可以识别哪些提交标记。 (实际上对于分支名称也是如此。)然后,您可以使用git log --decorate查看此标记,而gitk等图形查看器通常会显示哪些提交也包含哪些标记。

(搜索和标记是更好地过渡到这一点的好方法,至少在理论上是习惯。)

答案 1 :(得分:1)

在您开始工作之前,我假设您的dev分支跟踪master。如果没有,请在进行任何临时提交之前创建一个新分支。

要确定从master分支的点(以及重置为的点),请执行以下操作:

git merge-base master HEAD

您可以显示该点与HEAD之间的所有提交(这应包括您的所有临时提交,仅包括那些提交):

git log --oneline $(git merge-base master HEAD)..HEAD

您可以将该命令的输出传递给wc -l并获取提交次数,这是您git reset命令所需的数量。

或者,您可以直接使用以下内容获取该号码:

git rev-list --count $(git merge-base master HEAD)..HEAD

全部放在一起:

git reset --soft HEAD~$(git log --oneline $(git merge-base master HEAD)..HEAD | wc -l)

或者:

git reset --soft HEAD~$(git rev-list --count $(git merge-base master HEAD)..HEAD)

执行重置后,不是将squash_branch合并到dev中,而是更好地进行硬重置(在您确认没有任何内容被破坏之后):

git checkout dev
git reset --hard squash_branch

此外,合并冲突往往是有原因的,所以我要小心翼翼地强行推进遥控器。如果必须强制推送,请改为执行此操作:

git push origin master --force-with-lease

--force-with-lease标志将导致Git覆盖您已经提取的任何提交,但如果远程具有您不知道的新提交,该命令将失败。