使用git隔离一个更改与另一个更改

时间:2011-08-05 17:40:46

标签: git version-control github

我一直在我的本地主分支上开发一个尚未准备好进行生产推送的新功能。但是,我刚刚在我的实时应用程序中发现了一个单独的错误,所以我很快就在本地修复了它。但是,我想将这个错误修复推送到我的远程主分支,而不是推动我一直在努力的这个新功能。我怎么能这样做?

6 个答案:

答案 0 :(得分:3)

不太严肃的回答:

回到过去并使用适当的分支模型进行开发。停止在您的生产分支上工作并开始使用功能分支。您描述的情况正是您应该使用分支的原因:能够将开发工作放在一边,检查主数据,执行错误修复并返回到开发分支。通过忽略分支,你忽略了很多使Git很棒的东西。

更严肃的回答:

更实际的是,您可以重新排序提交,将本地主服务器指向要推送的服务,推送,然后将开发提交检查为新分支。

如果您的提交历史记录如下:

A <-- (master) bug fix, you want to push this
B <-- you don't want to push this
C <-- (origin/master)

您可以使用git rebase -i HEAD~2重新排序最后两次提交,看起来像这样(只需在出现的编辑器中切换行的顺序):

B <-- (master) you don't want to push this
A <-- bug fix
C <-- (origin/master)

记下B的SHA1,您即将暂时将其从主分支中删除。记录SHA1后,您可以使用git update-ref refs/heads/master [SHA1 of A],结果为

A <-- (master) bug fix
C <-- (origin/master)

您现在可以git pushA合并到origin/master并将结果发送到origin

最后,为了让你的开发工作(提交B)回来,创建一个新的开发分支(你应该首先完成)指向你的B提交:{{1} }

您的存储库现在看起来像这样:

git branch development [SHA1 of B]

当您准备好将开发工作合并到master中时,您可以:

B <-- (development) you don't want to push this
A <-- (master,origin/master) bug fix
C <-- where origin/master *was* before pushing

答案 1 :(得分:1)

你得到的答案很好,但有点复杂。我希望稍微简化一下。以下假定您仅在一个提交中提交了修复,最后一个提交在本地master分支上。

git branch new-feature master~1
git checkout -b bugfix
git branch -f master origin/master
git rebase --onto master new-feature

这会将你的新功能的工作放在它自己的分支上,称为new-feature,将你的bug修复程序放在它自己的独立分支上,称为bugfix,重置你的主分支以匹配你上次推送的内容,然后重新删除以删除新功能从您的错误修复分支工作。

这就是您通常希望分支机构在这一点上看到的方式。我是如何理解它的还不是非常重要的,因为将来你只需要在开始处理另一个新功能或错误修复之前用git checkout -b another-new-feature master创建一个新的分支。

现在,只推送你的错误修正,只需:

git checkout master
git merge bugfix
git push

然后继续处理新功能,请执行以下操作:

git checkout new-feature

如果要在新功能分支中包含错误修复,请执行以下操作:

git rebase master

否则,在您进行下一次推送之前,它将被合并。当您准备推送新功能时,只需执行与bugfix分支相同的合并,但使用new-feature分支。

答案 2 :(得分:0)

您只能将要提交的文件添加到暂存区域并在分支上提交它们。然后创建另一个分支并提交您不想提交的文件。然后你只需用修复程序推动分支。

当你提交时,它只会在你的临时区域中添加文件,这样你就可以在一个分支上提交你的一部分工作,而在另一个分支上提交你工作的另一部分。

如果要在使用非提交文件时切换分支,可以将它们添加到暂存区域,签出另一个分支,然后将暂存区域提交到另一个分支。

如果你做了一些想要推动的改变而有些改变你不想推送同一个文件那么它会变得更复杂。

答案 3 :(得分:0)

  1. 交互式rebase并将错误修复提交移动到changeset的第一次提交
  2. 创建一个指向错误修复提交的新分支
  3. 将新的错误修复分支推送到远程主控
  4. 我今天没有正常的测试机器,因此语法来自内存。如果有的话,有人可以打电话给我。

    不确定ascii艺术是否有效:

      [origin/master]  hash_0 blah
      [new_feature  ]  hash_1 feature progress: more widgets!
                       hash_2 feature progress: less widgets, what was I thinking?
                       hash_3 bug fix: fixed memory management
    

    命令可能如下所示:

    我将假设我们正在分支新功能。

    git rebase -i origin/master
    

    此时您将获得提交列表:

    hash_1 feature progress: more widgets!
    hash_2 feature progress: less widgets, what was I thinking?
    hash_3 bug fix: fixed memory management
    

    您将对提交进行重新排序:

    hash_3 bug fix: fixed memory management
    hash_1 feature progress: more widgets!
    hash_2 feature progress: less widgets, what was I thinking?
    

    如果您在此处收到错误,那么您的错误修复取决于您的新功能更改。很难就此提出建议。通常我只是在那种情况下重新创建origin / master中的错误修复。

      [origin/master]  hash_0 blah
      [new_feature  ]  hash_3 bug fix: fixed memory management
                       hash_1 feature progress: more widgets!
                       hash_2 feature progress: less widgets, what was I thinking?
    

    我们应该按照正确的顺序,我通常打开gitk并在视觉上验证它看起来我的期望。您希望看到您的错误修复是origin / master之后的下一次提交。

    git checkout hash_3
    git branch some_bug_fix
    git push origin some_bug_fix:master
    git checkout new_feature
    git rebase origin/master
    

    最后一次改变可能是多余的。

      [origin/master]  hash_0 blah
                       hash_3 bug fix: fixed memory management
      [new_feature  ]  hash_1 feature progress: more widgets!
                       hash_2 feature progress: less widgets, what was I thinking?
    

    或者,

    1. 结帐远程
    2. Cherry挑选错误修复提交。
    3. 这会复制本地分支中的代码,因此您需要将其从本地分支中删除并在master上进行rebase。

      我总是使用gitk来挑选,无法帮助你完成命令。

答案 4 :(得分:0)

Here是一个遍历命令的答案。我把它写成了一个类似的问题。

它的基础是,将您的错误修复移动到一个单独的分支,并将该分支与您的主和主题合并。不是在步骤4中修改更改,而是使用git cherry-pick bugFixSHA而不是从功能分支中删除提交。

答案 5 :(得分:0)

使用Git的“交互式添加”功能仅将错误修正添加到“临时区域”。然后,您可以隐藏其余的更改,测试错误修复以确保其有效,然后自行提交。

以下是演示示例。起初它可能看起来很长很复杂,但实际上很容易。一旦你完成了这几次,它将成为第二天性,你很可能会发现自己经常使用这种技术。


在此示例中,bar.cfoo.c都有变化,但只有foo.c有与错误修正相关的更改。首先,我使用git add -i以交互方式添加错误修正:

test(master *)$ git add -i
           staged     unstaged path
  1:    unchanged        +1/-0 bar.c
  2:    unchanged        +1/-1 foo.c

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help

我选择“p”选项告诉Git我希望选择要添加到“临时区域”的单个“补丁”:

What now> p
           staged     unstaged path
  1:    unchanged        +1/-0 bar.c
  2:    unchanged        +1/-1 foo.c

接下来我输入2告诉它我要从foo.c中选择单个补丁:

Patch update>> 2
           staged     unstaged path
  1:    unchanged        +1/-0 bar.c
* 2:    unchanged        +1/-1 foo.c

由于foo.c是唯一一个包含我要添加到“暂存区”的补丁的文件,现在我已经完成了选择文件,所以我只需在提示符下按Enter键:

Patch update>>

下一个Git向我展示了来自“foo.c”的各个补丁,并询问我是否要将它们添加到索引中。在这个例子中,只有一个变化,所以我暂存它:

diff --git a/foo.c b/foo.c
index 7bc741e..ec7ddfc 100644
--- a/foo.c
+++ b/foo.c
@@ -1 +1 @@
-Here is foo.c; it has a bug.
+Here is foo.c.
Stage this hunk [y,n,q,a,d,/,e,?]? y

我现在已经上演了bugfix的一部分。所以我退出了“交互式添加”模式:

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now> q
Bye.

注意状态。 foo.c已将更改添加到“暂存区域”,但“bar.c”不会:

test(master *+)$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   foo.c
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   bar.c
#

接下来我告诉Git隐藏我的工作,但要保留我已经添加到“临时区域”(a.k.a. “指数”):

test(master *+)$ git stash --keep-index
Saved working directory and index state WIP on master: ba84dec Adding bar.c with new "bar feature"
HEAD is now at ba84dec Adding bar.c with new "bar feature"
test(master +$)$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   foo.c
#

现在注意到我的工作树中唯一的东西是bug修复,它已准备好在下一次提交时提交。现在,在我提交之前,我可以对bugfix做任何我想做的测试。

当我对我的更改感到满意时,我现在可以提交错误修正:

test(master +$)$ git commit
[master 79acd00] Commit bugfix for foo.c
 1 files changed, 1 insertions(+), 1 deletions(-)

现在我弹出藏匿处,让我在bar.c做的其他工作回到我的工作树中:

test(master $)$ git stash pop
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   bar.c
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (d306d098a272335ed31c14f07cf57e62ffc13151)

我已经完成了。我现在可以推送到远程存储库,它将获得错误修复,而我的其余工作仍然在我的工作树中,并且不会被推送。