Git假装挤压

时间:2013-06-05 22:57:53

标签: git workflow

这个工作流程是否有什么问题可以获得类似的壁球结果?

  • 从名为draft_feature_a
  • 的主人签出一个新分支
  • 做一堆提交。一些提交破坏了代码。有些人提交了草率的提交信息。
  • 结帐主人,并从主人结帐新的分支feature_a
  • 通过git checkout draft_feature_a $(git diff --name-only master draft_feature_a)
  • 从草稿功能中提取最终更改

现在您只有最后的更改,您可以使用相当提交的消息提交它们。

3 个答案:

答案 0 :(得分:2)

它不会捕获文件删除,例如:

$ git checkout draft_feature_a $(git diff --name-only master draft_feature_a)
error: pathspec 'ttt.py' did not match any file(s) known to git.

你可以用实际的rebase-and-squash-etc做同样的事情(我在下面使用“fixup”,几乎是一样的,真​​的;原始提交仍然可以在draft_feature_a上查看):

$ git checkout -b draft_feature_a
[work, commit, etc - I made two commits: add newfile and rm ttt.py]
$ git checkout master
Switched to branch 'master'
$ git checkout -b feature_a
Switched to a new branch 'feature_a'
$ git merge draft_feature_a
Updating 523bacb..3a486fc
Fast-forward
 newfile |  0
 ttt.py  | 14 --------------
 2 files changed, 14 deletions(-)
 create mode 100644 newfile
 delete mode 100644 ttt.py
git rebase -i master
[edit to make everything but the first a "fixup"]
...
 2 files changed, 14 deletions(-)
 create mode 100644 newfile
 delete mode 100644 ttt.py
Successfully rebased and updated refs/heads/feature_a.
$ git commit --amend
[edit commit message]

我实际上使用这样的工作流程,虽然大多数时候我只是“git rebase -i”草稿工作。请注意,无论您是否创建单独的“草稿”分支,原始提交都可用,它们只是丢失了名称,您必须通过reflog来查找提交ID。您可以添加新名称而不是创建新分支和“git merge”-ing:

(首先,让我们清理上一个例子)

$ git checkout master
Switched to branch 'master'
$ git branch -D draft_feature_a
Deleted branch draft_feature_a (was 3a486fc).
$ git branch -D feature_a
Deleted branch feature_a (was 0fc36f0).

(现在是一个新例子)

$ git checkout -b feature_a
Switched to a new branch 'feature_a'
[work work work]
[time to clean up, let's stick a label on this version so I can find it easily:]
$ git branch messy_feature_a feature_a
$ git rebase -i master

一旦rebase完成,所有东西被压扁,修复,重新排列,提交消息编辑等等,如果我决定搞砸了什么,我所有的“草稿”(低质量/凌乱)工作在“凌乱”的名称下仍然可以使用名称。当我满意并且不想要旧名称时,我会手动删除它(git branch -D)。

理解这一点的诀窍是每次你在git中做东西时,你只会添加新的提交。旧的在你的回购中留下来,直到(最终)你做一些隐含的或明确的“垃圾收集”它们。只要它们具有分支标签名称(或其他“可见”名称,如标记),使得提交可以通过3a486fc样式SHA1名称之外的其他名称进行命名,它们将持续“永久”。删除分支只会删除标签。一个月或三个月后,未标记的提交最终被垃圾收集。 (更准确地说,它在reflog中仍有一个名称,直到过期:reflog条目有时间限制。请参阅git reflog的文档,尤其是--expire=<time>参数。)

类似地,“rebase”进行一系列新的提交,将所有旧提交留在那里。当rebase完成时,git将标签从旧系列提交的末尾剥离并粘贴到新系列提交的末尾:

A -- B -- C          [label: master]
           \
            D -- E   [label: feature_a]

[rebase feature_a on master, and squash or fixup to make commit DE which is D+E]

A -- B -- C          [label: master]
          | \
          |  D -- E  [no label!]
          \
            DE       [label: feature_a]

如果在执行rebase之前添加额外标签,则会剥离当前分支feature_a标签并移动到新提交,但另一个标签(messy_feature_a)会粘在一起并且让您轻松访问提交E,从而使整个链(D和E分支C)。

答案 1 :(得分:1)

您似乎使用的是Linux风格的系统$(git...。这应该工作,并将处理已删除的文件:

git checkout -b feature_a master
git diff draft_feature_a | patch -p1 -R

答案 2 :(得分:0)

这是我的新工作流程:

  • 从名为draft_feature_a
  • 的主人签出一个新分支
  • 做一堆提交。一些提交破坏了代码。有些人提交了草率的提交信息。
  • master合并到draft_feature_a,并解决所有冲突。
  • draft_feature_a结帐新分行final_feature_agit checkout -b final_feature_a
  • git reset --soft master
  • 现在您只进行了最后的更改,并且可以使用相当提交的消息提交这些更改。

我知道我可以使用git rebase -i master和压缩来完成所有这些操作,但是当发生冲突时,我会感到很复杂。