如何在保留更改的同时从 Git 存储库中删除选定的提交日志条目?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/495345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 06:08:05  来源:igfitidea点击:

How to remove selected commit log entries from a Git repository while keeping their changes?

gitcommit

提问by xk0der

I would like to remove selected commit log entries from a linear commit tree, so that the entries do not show in the commit log.

我想从线性提交树中删除选定的提交日志条目,以便这些条目不会显示在提交日志中。

My commit tree looks something like:

我的提交树看起来像:

R--A--B--C--D--E--HEAD

I would like to remove the B and C entries so that they do not show in the commit log, but changes from A to D should be preserved. Maybe by introducing a single commit, so that B and C become BC and the tree looks like.

我想删除 B 和 C 条目,以便它们不会显示在提交日志中,但应保留从 A 到 D 的更改。也许通过引入单个提交,使 B 和 C 成为 BC 并且树看起来像。

R--A--BC--D--E--HEAD

Or, ideally, after A comes D directly. D' representing changes from A to B, B to C and C to D.

或者,理想情况下,在 A 之后直接出现 D。D' 代表从 A 到 B、B 到 C 和 C 到 D 的变化。

R--A--D'--E--HEAD

Is this possible? if yes, how?

这可能吗?如果是,如何?

This is a fairly new project so has no branches as of now, hence no merges as well.

这是一个相当新的项目,因此目前没有分支,因此也没有合并。

回答by jfs

git-rebase(1)does exactly that.

git-rebase(1)正是这样做的。

$ git rebase -i HEAD~5

git awsome-ness [git rebase --interactive]contains an example.

git awsome-ness [git rebase --interactive]包含一个示例。

  1. Don't use git-rebaseon public (remote) commits.
  2. Make sure your working directory is clean (commitor stashyour current changes).
  3. Run the above command. It launches your $EDITOR.
  4. Replace pickbefore Cand Dby squash. It will meld C and D into B. If you want to delete a commit then just delete its line.
  1. 不要git-rebase在公共(远程)提交上使用。
  2. 确保您的工作目录是干净的(commitstash您当前的更改)。
  3. 运行上面的命令。它启动您的$EDITOR.
  4. 替换pick之前CD之后squash。它会将 C 和 D 融合到 B 中。如果你想删除一个提交,那么只需删除它的行。

If you are lost, type:

如果您迷路了,请输入:

$ git rebase --abort  

回答by CB Bailey

# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master

回答by rado

Here is a way to remove a specific commit id knowing only the commit id you would like to remove.

这是一种删除特定提交 ID 的方法,只知道您要删除的提交 ID。

git rebase --onto commit-id^ commit-id

Note that this actually removes the change that was introduced by the commit.

请注意,这实际上删除了提交引入的更改。

回答by idbrii

To expand on J.F. Sebastian's answer:

扩展 JF Sebastian 的回答:

You can use git-rebase to easily make all kinds of changes to your commit history.

您可以使用 git-rebase 轻松地对提交历史进行各种更改。

After running git rebase --interactive you get the following in your $EDITOR:

运行 git rebase --interactive 后,您会在 $EDITOR 中获得以下内容:

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

You can move lines to change the order of commits and delete lines to remove that commit. Or you can add a command to combine (squash) two commits into a single commit (previous commit is the above commit), edit commits (what was changed), or reword commit messages.

您可以移动行以更改提交的顺序并删除行以删除该提交。或者,您可以添加一个命令将两个提交合并(压缩)为一个提交(前一个提交是上面的提交)、编辑提交(更改的内容)或重新编写提交消息。

I think pick just means that you want to leave that commit alone.

我认为选择只是意味着你想不理会那个提交。

(Example is from here)

(示例来自此处

回答by Head

You can non-interactively removeB and C in your example with:

您可以使用以下命令以非交互方式删除示例中的B 和 C:

git rebase --onto HEAD~5 HEAD~3 HEAD

or symbolically,

或象征性地,

git rebase --onto A C HEAD

Note that the changes in B and C will notbe in D; they will be gone.

注意 B 和 C 的变化不会在 D 中;他们会消失的

回答by resultsway

One more way,

还有一种方式,

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

pick the hash that you want to use it as a base, and the above command should make it interactive so you can squash all the topmessages ( you need to leave the oldest )

选择你想用它作为基础的散列,上面的命令应该使它具有交互性,这样你就可以压缩所有的顶部消息(你需要留下最旧的)

回答by Eric Woodruff

I find this process much safer and easier to understand by creating another branch from the SHA1 of A and cherry-picking the desired changes so I can make sure I'm satisfied with how this new branch looks. After that, it is easy to remove the old branch and rename the new one.

通过从 A 的 SHA1 创建另一个分支并挑选所需的更改,我发现这个过程更安全、更容易理解,这样我就可以确保我对这个新分支的外观感到满意。之后,很容易删除旧分支并重命名新分支。

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>

回答by Shrinath Kopare

Just collected all people's answers:(m new to git plz use it for reference only)

刚刚收集了所有人的答案:(我是git新手,仅供参考)

git rebase to delete any commits

git rebase 删除任何提交

git log

混帐日志

-first check from which commit you want to rebase

git rebase -i HEAD~1

git rebase -i HEAD~1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

Then the screen will look something like this:

然后屏幕看起来像这样:

pick 0c2236d Added new line.

Rebase 2a1cd65..0c2236d onto 2a1cd65 (1 command)

#

Commands:

p, pick = use commit

r, reword = use commit, but edit the commit message

e, edit = use commit, but stop for amending

s, squash = use commit, but meld into previous commit

f, fixup = like "squash", but discard this commit's log message

x, exec = run command (the rest of the line) using shell

d, drop = remove commit

#

These lines can be re-ordered; they are executed from top to bottom.

#

If you remove a line here THAT COMMIT WILL BE LOST.

#

However, if you remove everything, the rebase will be aborted.

#

Note that empty commits are commented out ~ ~

~
~
~
~
~
~
~
~
~

选择 0c2236d 添加了新行。

将 2a1cd65..0c2236d 变基到 2a1cd65(1 个命令)

#

命令:

p, 选择 = 使用提交

r, reword = 使用提交,但编辑提交信息

e, edit = 使用提交,但停止修改

s, squash = 使用提交,但融合到之前的提交中

f, fixup = like "squash", 但丢弃这个提交的日志信息

x, exec = 使用 shell 运行命令(该行的其余部分)

d, drop = 删除提交

#

这些行可以重新排序;它们是从上到下执行的。

#

如果您在此处删除一行,则提交将丢失。

#

但是,如果您删除所有内容,则变基将中止。

#

注意空提交被注释掉~~

~
~
~
~
~
~
~
~
~ ~

Here change the first line as per your need (using the commands listed above i.e. 'drop' to remove commit etc.) Once done the editing press ':x' to save and exit editor(this is for vim editor only)

这里根据您的需要更改第一行(使用上面列出的命令,即“drop”删除提交等)完成编辑后按“:x”保存并退出编辑器(这仅适用于 vim 编辑器)

And then

进而

git push

If its showing problem then you need to forcefully push the changes to remote(ITS VERY CRITICAL : dont force push if you are working in team)

如果它显示问题,那么您需要强制将更改推送到远程(非常关键:如果您在团队中工作,请不要强制推送)

git push -f origin

git push -f 原点

回答by Rory

You can use git cherry-pick for this. 'cherry-pick' will apply a commit onto the branch your on now.

您可以为此使用 git cherry-pick。'cherry-pick' 会将提交应用到您现在所在的分支上。

then do

然后做

git rebase --hard <SHA1 of A>

then apply the D and E commits.

然后应用 D 和 E 提交。

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

This will skip out the B and C commit. Having said that it might be impossible to apply the D commit to the branch without B, so YMMV.

这将跳过 B 和 C 提交。话虽如此,没有 B 可能无法将 D 提交应用于分支,所以 YMMV。