1

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

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

现在您已经有了最后的更改,您可以使用漂亮的提交消息提交这些更改。

4

3 回答 3

2

It won't capture file removals, for instance:

$ 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.

You can do the same thing with an actual rebase-and-squash-etc (I used "fixup" below, pretty much the same thing, really; the original commits are all still viewable on 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]

I actually use workflows like this a lot, although most of the time I'll just "git rebase -i" the draft work. Note that the original commits are available whether or not you make a separate "draft" branch, they just lose their name and you have to dig through the reflog to find the commit ID. You can add a new name instead of making a new branch and "git merge"-ing:

(first, let's clean up the previous example)

$ 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).

(now a new example)

$ 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

Once the rebase is done, with everything squashed, fixed-up, rearranged, commit message(s) edited, etc., if I decide I screwed something up, all my "draft" (low-quality/messy) work is still available by name under the "messy" name. When I'm satisfied, and don't want the old name, I delete it manually (git branch -D).

The trick to understanding this is that every time you do stuff in git, you only ever add new commits. The old ones stick around in your repo until (eventually) you do something implicit or explicit to "garbage collect" them. As long as they have a branch label name (or some other "visible" name, like a tag) that makes the commits name-able by something other than the 3a486fc style SHA1 names, they last "forever". Deleting a branch simply erases the label. After a month or three, the unlabeled commits are finally garbage-collected. (More precisely, it still has a name in the reflog, until that expires: reflog entries have a time limit. See the documentation for git reflog, especially the --expire=<time> parameter.)

Similarly, a "rebase" makes a new series of commits, leaving all the old commits in there. When the rebase is done git peels the label off the end of the old series of commits and pastes it onto the end of the new series of commits:

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]

If you add an extra label before doing the rebase, the current-branch feature_a label is peeled off and moved to the new commit(s), but the other label (messy_feature_a) sticks around and gives you easy access to commit E, and hence the entire chain (D and E branching off C).

于 2013-06-06T01:33:42.947 回答
1

看来您使用的是 linux 风格的系统$(git...。这应该可以工作并且会处理已删除的文件:

git checkout -b feature_a master
git diff draft_feature_a | patch -p1 -R
于 2013-06-06T01:48:56.427 回答
0

这是我的新工作流程:

  • 从 master 签出一个名为的新分支draft_feature_a
  • 做一堆提交。一些提交会破坏代码。有些有草率的提交消息。
  • 合并masterdraft_feature_a,并解决任何冲突。
  • draft_feature_a结帐一个新的分支final_feature_agit checkout -b final_feature_a
  • git reset --soft master
  • 现在您已经有了最后的更改,您可以使用漂亮的提交消息提交这些更改。

我知道我可以用 agit rebase -i master和 squashing 来完成这一切,但是当有冲突时,它对我来说变得很复杂。

于 2015-03-03T02:00:57.080 回答