git 将先前的提交分解为多个提交

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6217156/
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 11:04:39  来源:igfitidea点击:

Break a previous commit into multiple commits

git

提问by koblas

Without creating a branch and doing a bunch of funky work on a new branch, is it possible to break a single commit into a few different commits after it's been committed to the local repository?

如果不创建分支并在新分支上做一堆时髦的工作,是否可以在将单个提交提交到本地存储库后将其分解为几个不同的提交?

回答by Wayne Conrad

git rebase -iwill do it.

git rebase -i会做的。

First, start with a clean working directory: git statusshould show no pending modifications, deletions, or additions.

首先,从一个干净的工作目录开始:git status不应显示未决的修改、删除或添加。

Now, you have to decide which commit(s) you want to split.

现在,您必须决定要拆分哪些提交。

A) Splitting the most recent commit

A) 拆分最近的提交

To split apart your most recent commit, first:

要拆分您最近的提交,首先:

$ git reset HEAD~

Now commit the pieces individually in the usual way, producing as many commits as you need.

现在以通常的方式单独提交这些片段,根据需要生成尽可能多的提交。

B) Splitting a commit farther back

B) 向后拆分提交

This requires rebasing, that is, rewriting history. To find the correct commit, you have several choices:

这需要rebase,即重写历史。要找到正确的提交,您有多种选择:

  • If it was three commits back, then

    $ git rebase -i HEAD~3
    

    where 3is how many commits back it is.

  • If it was farther back in the tree than you want to count, then

    $ git rebase -i 123abcd~
    

    where 123abcdis the SHA1 of the commit you want to split up.

  • If you are on a different branch (e.g., a feature branch) that you plan to merge into master:

    $ git rebase -i master
    
  • 如果是三个提交,那么

    $ git rebase -i HEAD~3
    

    3返回的提交数量在哪里。

  • 如果它在树中比你想数的更远,那么

    $ git rebase -i 123abcd~
    

    123abcd您要拆分的提交的 SHA1在哪里。

  • 如果您在计划合并到 master 的不同分支(例如,功能分支)上:

    $ git rebase -i master
    

When you get the rebase edit screen, find the commit you want to break apart. At the beginning of that line, replace pickwith edit(efor short). Save the buffer and exit. Rebase will now stop just after the commit you want to edit. Then:

当您看到 rebase 编辑屏幕时,找到您想要拆分的提交。在该行的开头,替换pickedit(e简称)。保存缓冲区并退出。Rebase 现在将在您要编辑的提交之后停止。然后:

$ git reset HEAD~

Commit the pieces individually in the usual way, producing as many commits as you need, then

以通常的方式单独提交各个部分,根据需要生成尽可能多的提交,然后

$ git rebase --continue

回答by MBO

From git-rebasemanual (SPLITTING COMMITS section)

来自git-rebase手册(拆分提交部分)

In interactive mode, you can mark commits with the action "edit". However, this does not necessarily mean that git rebase expects the result of this edit to be exactly one commit. Indeed, you can undo the commit, or you can add other commits. This can be used to split a commit into two:

  • Start an interactive rebase with git rebase -i <commit>^, where <commit>is the commit you want to split. In fact, any commit range will do, as long as it contains that commit.

  • Mark the commit you want to split with the action "edit".

  • When it comes to editing that commit, execute git reset HEAD^. The effect is that the HEAD is rewound by one, and the index follows suit. However, the working tree stays the same.

  • Now add the changes to the index that you want to have in the first commit. You can use git add(possibly interactively) or git gui(or both) to do that.

  • Commit the now-current index with whatever commit message is appropriate now.

  • Repeat the last two steps until your working tree is clean.

  • Continue the rebase with git rebase --continue.

在交互模式下,您可以使用“编辑”操作标记提交。但是,这并不一定意味着 git rebase 期望此编辑的结果恰好是一次提交。实际上,您可以撤消提交,也可以添加其他提交。这可用于将提交拆分为两个:

  • 使用 开始交互式变基git rebase -i <commit>^<commit>您要拆分的提交在哪里。事实上,任何提交范围都可以,只要它包含该提交。

  • 使用“编辑”操作标记要拆分的提交。

  • 在编辑该提交时,执行git reset HEAD^. 效果是HEAD倒退1,索引也跟着。但是,工作树保持不变。

  • 现在将更改添加到您希望在第一次提交中拥有的索引。您可以使用git add(可能以交互方式)或git gui(或两者)来做到这一点。

  • 使用现在合适的任何提交消息提交现在当前的索引。

  • 重复最后两个步骤,直到您的工作树干净为止。

  • 继续使用git rebase --continue.

回答by Rose Perrone

Use git rebase --interactiveto edit that earlier commit, run git reset HEAD~, and then git add -pto add some, then make a commit, then add some more and make another commit, as many times as you like. When you're done, run git rebase --continue, and you'll have all the split commits earlier in your stack.

使用git rebase --interactive到编辑早些时候提交,运行git reset HEAD~,然后再git add -p添加一些,然后再做出承诺,然后添加一些再拍承诺,多次你喜欢。完成后,运行git rebase --continue,您将在堆栈中更早地拥有所有拆分提交。

Important: Note that you can play around and make all the changes you want, and not have to worry about losing old changes, because you can always run git reflogto find the point in your project that contains the changes you want, (let's call it a8c4ab), and then git reset a8c4ab.

重要提示:请注意,您可以随意进行更改并进行所需的所有更改,而不必担心丢失旧的更改,因为您始终可以运行git reflog以找到项目中包含您想要的更改的点(我们称之为a8c4ab) ,然后git reset a8c4ab

Here's a series of commands to show how it works:

下面是一系列命令来展示它是如何工作的:

mkdir git-test; cd git-test; git init

mkdir git-test; cd git-test; git init

now add a file A

现在添加一个文件 A

vi A

vi A

add this line:

添加这一行:

one

one

git commit -am one

git commit -am one

then add this line to A:

然后将此行添加到A:

two

two

git commit -am two

git commit -am two

then add this line to A:

然后将此行添加到A:

three

three

git commit -am three

git commit -am three

now the file A looks like this:

现在文件 A 看起来像这样:

one
two
three

and our git loglooks like the following (well, I use git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

和我们的git log样子如下(嗯,我用git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

bfb8e46 Rose Perrone 4 seconds ago ---- three
2b613bc Rose Perrone 14 seconds ago ---- two
9aac58f Rose Perrone 24 seconds ago ---- one

Let's say we want to split the second commit, two.

假设我们要拆分第二次提交,two.

git rebase --interactive HEAD~2

git rebase --interactive HEAD~2

This brings up a message that looks like this:

这会显示一条消息,如下所示:

pick 2b613bc two
pick bfb8e46 three

Change the first pickto an eto edit that commit.

将第pick一个更改为 ane以编辑该提交。

git reset HEAD~

git reset HEAD~

git diffshows us that we just unstaged the commit we made for the second commit:

git diff向我们展示了我们刚刚取消了为第二次提交所做的提交:

diff --git a/A b/A
index 5626abf..814f4a4 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two

Let's stage that change, and add "and a third" to that line in file A.

让我们暂存该更改,并在 file 中的该行中添加“和第三个” A

git add .

git add .

This is usually the point during an interactive rebase where we would run git rebase --continue, because we usually just want to go back in our stack of commits to edit an earlier commit. But this time, we want to create a new commit. So we'll run git commit -am 'two and a third'. Now we edit file Aand add the line two and two thirds.

这通常是我们将运行的交互式 rebase 期间的点git rebase --continue,因为我们通常只想回到我们的提交堆栈中以编辑较早的提交。但是这一次,我们要创建一个新的提交。所以我们会跑git commit -am 'two and a third'。现在我们编辑文件A并添加行two and two thirds

git add .git commit -am 'two and two thirds'git rebase --continue

git add .git commit -am 'two and two thirds'git rebase --continue

We have a conflict with our commit, three, so let's resolve it:

我们与我们的提交有冲突three,所以让我们解决它:

We'll change

我们会改变

one
<<<<<<< HEAD
two and a third
two and two thirds
=======
two
three
>>>>>>> bfb8e46... three

to

one
two and a third
two and two thirds
three

git add .; git rebase --continue

git add .; git rebase --continue

Now our git log -plooks like this:

现在我们的git log -p样子是这样的:

commit e59ca35bae8360439823d66d459238779e5b4892
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 13:57:00 2013 -0700

    three

diff --git a/A b/A
index 5aef867..dd8fb63 100644
--- a/A
+++ b/A
@@ -1,3 +1,4 @@
 one
 two and a third
 two and two thirds
+three

commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 14:07:07 2013 -0700

    two and two thirds

diff --git a/A b/A
index 575010a..5aef867 100644
--- a/A
+++ b/A
@@ -1,2 +1,3 @@
 one
 two and a third
+two and two thirds

commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 14:06:40 2013 -0700

    two and a third

diff --git a/A b/A
index 5626abf..575010a 100644
--- a/A
+++ b/A
@@ -1 +1,2 @@
 one
+two and a third

commit 9aac58f3893488ec643fecab3c85f5a2f481586f
Author: Rose Perrone <[email protected]>
Date:   Sun Jul 7 13:56:40 2013 -0700

    one

diff --git a/A b/A
new file mode 100644
index 0000000..5626abf
--- /dev/null
+++ b/A
@@ -0,0 +1 @@
+one

回答by Andy Mortimer

Previous answers have covered the use of git rebase -ito edit the commit that you want to split, and committing it in parts.

以前的答案涵盖了使用git rebase -i来编辑要拆分的提交,并分部分提交。

This works well when splitting the files into different commits, but if you want to break apart changes to the individual files, there's more you need to know.

这在将文件拆分为不同的提交时效果很好,但是如果您想拆分对单个文件的更改,则需要了解更多信息。

Having got to the commit you want to split, using rebase -iand marking it for edit, you have two options.

到了要拆分的提交,使用rebase -i它并将其标记为 后edit,您有两个选择。

  1. After using git reset HEAD~, go through the patches individually using git add -pto select the ones you want in each commit

  2. Edit the working copy to remove the changes you do not want; commit that interim state; and then pull back the full commit for the next round.

  1. 使用后git reset HEAD~,单独浏览补丁使用git add -p以在每次提交中选择您想要的补丁

  2. 编辑工作副本以删除您不想要的更改;提交那个临时状态;然后拉回下一轮的完整提交。

Option 2 is useful if you're splitting a large commit, as it lets you check that the interim versions build and run properly as part of the merge. This proceeds as follows.

如果您要拆分大型提交,则选项 2 很有用,因为它可以让您检查临时版本是否作为合并的一部分正确构建和运行。这如下进行。

After using rebase -iand editing the commit, use

使用rebase -iediting 提交后,使用

git reset --soft HEAD~

to undo the commit, but leave the committed files in the index. You can also do a mixed reset by omitting --soft, depending on how close to the final result your initial commit is going to be. The only difference is whether you start with all the changes staged or with them all unstaged.

撤消提交,但将提交的文件保留在索引中。您还可以通过省略 --soft 来进行混合重置,具体取决于您的初始提交与最终结果的接近程度。唯一的区别是您是从所有更改开始还是从所有更改开始。

Now go in and edit the code. You can remove changes, delete added files, and do whatever you want to construct the first commit of the series you're looking for. You can also build it, run it, and confirm that you have a consistent set of source.

现在进去编辑代码。您可以删除更改、删除添加的文件,并执行任何您想要构建您正在查找的系列的第一个提交的操作。您还可以构建、运行它,并确认您拥有一组一致的源代码。

Once you're happy, stage/unstage the files as needed (I like to use git guifor this), and commit the changes through the UI or the command line

满意后,根据需要暂存/取消暂存文件(我喜欢git gui用于此目的),并通过 UI 或命令行提交更改

git commit

That's the first commit done. Now you want to restore your working copy to the state it had after the commit you are splitting, so that you can take more of the changes for your next commit. To find the sha1 of the commit you're editing, use git status. In the first few lines of the status you'll see the rebase command that is currently executing, in which you can find the sha1 of your original commit:

这是第一次提交。现在,您希望将工作副本恢复到拆分提交后的状态,以便您可以为下一次提交进行更多更改。要查找您正在编辑的提交的 sha1,请使用git status. 在状态的前几行中,您将看到当前正在执行的 rebase 命令,您可以在其中找到原始提交的 sha1:

$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
   pick 4847406 US135756: add debugging to the file download code
   e 65dfb6a US135756: write data and download from remote
  (see more in file .git/rebase-merge/done)
...

In this case, the commit I'm editing has sha1 65dfb6a. Knowing that, I can check out the content of that commit over my working directory using the form of git checkoutwhich takes both a commit and a file location. Here I use .as the file location to replace the whole working copy:

在这种情况下,我正在编辑的提交具有 sha1 65dfb6a。知道了这一点,我可以使用git checkout提交和文件位置的形式在我的工作目录中检查该提交的内容。这里我使用.作为文件位置来替换整个工作副本:

git checkout 65dfb6a .

Don't miss the dot on the end!

不要错过最后的点!

This will check out, and stage, the files as they were after the commit you're editing, but relative to the previous commit you made, so any changes you already committed won't be part of the commit.

这将检出和暂存文件,因为它们在您正在编辑的提交之后,但相对于您之前所做的提交,因此您已经提交的任何更改都不会成为提交的一部分。

You can either go ahead now and commit it as-is to finish the split, or go around again, deleting some parts of the commit before making another interim commit.

您可以现在继续并按原样提交以完成拆分,或者再次进行,在进行另一个临时提交之前删除提交的某些部分。

If you want to reuse the original commit message for one or more commits, you can use it straight from the rebase's working files:

如果您想为一个或多个提交重用原始提交消息,您可以直接从 rebase 的工作文件中使用它:

git commit --file .git/rebase-merge/message

Finally, once you've committed all the changes,

最后,一旦您提交了所有更改,

git rebase --continue

will carry on and complete the rebase operation.

将继续并完成 rebase 操作。

回答by Andy Mortimer

git rebase --interactivecan be used to split a commit into smaller commits. The Git docs on rebase have a concise walkthrough of the process - Splitting Commits:

git rebase --interactive可用于将提交拆分为较小的提交。rebase 上Git 文档对该过程进行了简明的演练 - 拆分提交

In interactive mode, you can mark commits with the action "edit". However, this does not necessarily mean that git rebaseexpects the result of this edit to be exactly one commit. Indeed, you can undo the commit, or you can add other commits. This can be used to split a commit into two:

  • Start an interactive rebase with git rebase -i <commit>^, where <commit>is the commit you want to split. In fact, any commit range will do, as long as it contains that commit.

  • Mark the commit you want to split with the action "edit".

  • When it comes to editing that commit, execute git reset HEAD^. The effect is that the HEAD is rewound by one, and the index follows suit. However, the working tree stays the same.

  • Now add the changes to the index that you want to have in the first commit. You can use git add(possibly interactively) or git gui (or both) to do that.

  • Commit the now-current index with whatever commit message is appropriate now.

  • Repeat the last two steps until your working tree is clean.

  • Continue the rebase with git rebase --continue.

If you are not absolutely sure that the intermediate revisions are consistent (they compile, pass the testsuite, etc.) you should use git stashto stash away the not-yet-committed changes after each commit, test, and amend the commit if fixes are necessary.

在交互模式下,您可以使用“编辑”操作标记提交。但是,这并不一定意味着git rebase期望此编辑的结果恰好是一次提交。实际上,您可以撤消提交,也可以添加其他提交。这可用于将提交拆分为两个:

  • 使用 开始交互式变基git rebase -i <commit>^<commit>您要拆分的提交在哪里。事实上,任何提交范围都可以,只要它包含该提交。

  • 使用“编辑”操作标记要拆分的提交。

  • 在编辑该提交时,执行git reset HEAD^. 效果是HEAD倒退1,索引也跟着。但是,工作树保持不变。

  • 现在将更改添加到您希望在第一次提交中拥有的索引。您可以使用git add(可能以交互方式)或 git gui(或两者)来做到这一点。

  • 使用现在合适的任何提交消息提交现在当前的索引。

  • 重复最后两个步骤,直到您的工作树干净为止。

  • 继续使用git rebase --continue.

如果您不确定中间版本是否一致(它们编译、通过测试套件等),您应该git stash在每次提交、测试和修改提交(如果需要修复)之后使用它来隐藏尚未提交的更改.

回答by Mika?l Mayer

Now in the latest TortoiseGit on Windows you can do it very easily.

现在,在 Windows 上最新的 TortoiseGit 中,您可以非常轻松地做到这一点。

Open the rebase dialog, configure it, and do the following steps.

打开 rebase 对话框,配置它,然后执行以下步骤。

  • Right-click the commit you want to split and select "Edit" (among pick, squash, delete...).
  • Click "Start" to start rebasing.
  • Once it arrives to the commit to split, check the "Edit/Split" button and click on "Amend" directly. The commit dialog opens.
    Edit/Split commit
  • Unselect the files you want to put on a separate commit.
  • Edit the commit message, and then click "commit".
  • Until there are files to commit, the commit dialog will open again and again. When there is no more file to commit, it will still ask you if you want to add one more commit.
  • 右键单击要拆分的提交并选择“ Edit”(在选择、压缩、删除...中)。
  • 单击“ Start”开始变基。
  • 一旦到达要拆分的提交,请选中“ Edit/Split”按钮并Amend直接单击“ ”。提交对话框打开。
    编辑/拆分提交
  • 取消选择要单独提交的文件。
  • 编辑提交消息,然后单击“ commit”。
  • 在有文件要提交之前,提交对话框将一次又一次地打开。当没有更多文件要提交时,它仍然会询问您是否要再添加一个提交。

Very helpful, thanks TortoiseGit !

非常有帮助,感谢 TortoiseGit!

回答by manojlds

You can do interactive rebase git rebase -i. Man page has exactly what you want:

你可以做交互式 rebase git rebase -i。手册页正是您想要的:

http://git-scm.com/docs/git-rebase#_splitting_commits

http://git-scm.com/docs/git-rebase#_splitting_commits

回答by lethalman

Please note there's also git reset --soft HEAD^. It's similar to git reset(which defaults to --mixed) but it retains the index contents. So that if you've added/removed files, you have them in the index already.

请注意,还有git reset --soft HEAD^. 它类似于git reset(默认为--mixed),但它保留了索引内容。因此,如果您添加/删除了文件,则它们已经在索引中。

Turns out to be very useful in case of giant commits.

事实证明,在大量提交的情况下非常有用。

回答by bzuo

Here is how to split one commit in IntelliJ IDEA, PyCharm, PhpStormetc

以下是如何在IntelliJ IDEAPyCharmPhpStorm等中拆分一次提交

  1. In Version Control log window, select the commit you would like to split, right click and select the Interactively Rebase from Here

  2. mark the one you want to split as edit, click Start Rebasing

  3. You should see a yellow tag is placed meaning that the HEAD is set to that commit. Right click on that commit, select Undo Commit

  4. Now those commits are back to staging area, you can then commit them separately. After all change has been committed, the old commit becomes inactive.

  1. 在版本控制日志窗口中,选择要拆分的提交,右键单击并选择 Interactively Rebase from Here

  2. 将要拆分的标记为edit,单击Start Rebasing

  3. 您应该看到放置了一个黄色标记,这意味着 HEAD 设置为该提交。右键单击该提交,选择Undo Commit

  4. 现在这些提交返回到暂存区,然后您可以单独提交它们。提交所有更改后,旧提交将变为非活动状态。

回答by Nguyen Sy Thanh Son

I think that the best way i use git rebase -i. I created a video to show the steps to split a commit: https://www.youtube.com/watch?v=3EzOz7e1ADI

我认为这是我使用的最佳方式git rebase -i。我创建了一个视频来展示拆分提交的步骤:https: //www.youtube.com/watch?v=3EzOz7e1ADI