Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git 修改commit历史的常用方法 #10

Open
waltcow opened this issue Feb 14, 2017 · 0 comments
Open

Git 修改commit历史的常用方法 #10

waltcow opened this issue Feb 14, 2017 · 0 comments

Comments

@waltcow
Copy link
Owner

waltcow commented Feb 14, 2017

开发时经常会出现以下场景

请把你当前分支与master 最新版本做一次rebase,我们在合并你的PR
你把你几个commits squash成一个commit,避免git历史过于复杂和难看
你去把你commit 的message修改一下,使得commit 的信息让人更清晰易懂

上述的这些问题常见于PR下面的讨论,下面总结一下解决问题的方法

重写最近的commit 的信息

在提交后, 如果你发现在其描述中发现typo,或者找到一个更好的方式来描述commit。要进行校正:

git commit --amend

这时git将进入编辑模式,在这里你可以修改之前的commit 的相关信息

除了简单的编辑commit记录之外,你也可以单单修改coomit的author

git commit --amend --author="waltcow <waltcow@gmail.com>"

修改其它的commit的内容

使用 Interactive Rebase 模式

git rebase 重新把每次的提交一个一个按顺序apply在当前的branch上。git rebase 接受几个使用的option,其中有个非常实用的就是 --interactive- i 是对应的shortcut),进入Interactive Rebase 模式后,git将打开编辑器,list出包含的改动信息,这些list的每行开始都接受command ,用户可以决定相关操作的参数后再进行rebase

详细可以见下面的相关例子

现在我要重写当前分支上最后4个commit的信息,我只需要

git rebase -i HEAD~4

下面我们将会看到

pick 07c5abd Introduce OpenPGP and teach basic usage
pick de9b1eb Fix PostChecker::Post#urls
pick 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

# Rebase 8db7e8b..fa20af3 onto 8db7e8b
#
# 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
#
# 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

上面我们可以看到最近的commit记录,时间排序从older=>newer,
下面有相关的command的使用介绍,如下将逐一介绍

  • pick 这是默认的选择,就是把commit再重新apply一次而已,commit的内容和信息都不会有改动
  • reword commit的内容不变,仅仅把commit的message做修改

比如我把上面的commit改成

pick 07c5abd Introduce OpenPGP and teach basic usage
pick de9b1eb Fix PostChecker::Post#urls
reword 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend
+
When I save and quit the editor, git will follow the described commands, landing

当我:wq 后git 将会输出

robots.thoughtbot.com tc-git-rebase % git rebase -i HEAD~4
[detached HEAD dd62a66] Stop all the highlighting
 Author: Caleb Thompson
 Date: Fri Oct 31 10:52:26 2014 -0500
 2 files changed, 39 insertions(+), 42 deletions(-)
Successfully rebased and updated refs/heads/tc-git-rebase.

将多个commits Squash在一起

  • squash 将提交融合到前一个commit(上面的那一行)
  • fixup 类似于 squash,但是commit的message将会被丢弃

下面是使用案例
现在我们我4个commit,前三个commit是我同事改的,我自己的是最后一个

pick 07c5abd Introduce OpenPGP and teach basic usage
pick de9b1eb Fix PostChecker::Post#urls
pick 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

假如我现在想把我同事的修改合并在一起,以为前三个都是做一个的主题的,这样合并后的话,我们以后如果想revert这部分变更将变简单。
前三个commit中我想只保留第一个commit的message,后面两个的更改提交并压缩到第一个提交消息中

pick 07c5abd Introduce OpenPGP and teach basic usage
squash  de9b1eb Fix PostChecker::Post#urls
squash  3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

squash 的作用就是把当前commit向前合并,一直合并到pick为止
fixupsquash非常类似,把pick修改成fixup,同样会向前合并到pick,唯一的区别就是,fixup会忽略当前commit的信息,只会应用修改。

与远程master分支做 Rebase

当我们fork一个远程仓库,在一个功能分支上开始工作,并且upstream/maste将不断的前进。我们的历史看起来像:

      A---B---C feature
    /
D---E---F---G upstream/master


当仓库管理者在合并你的PR时都会教你 rebase on top of master,这样做可以避免merge时出现冲突,并保证了两个分支是基于一个parent 的,在rebase后你所看到的历史是这样的

A'--B'--C' feature
             /
D---E---F---G upstream/master

一般使用的命令

# Point our `upstream` remote to the original fork
git remote add upstream https://github.com/thoughtbot/factory_girl.git

# Fetch latest commits from `upstream` (the original fork)
git fetch upstream

# Checkout our feature branch
git checkout feature

# Reapply it onto upstream's master
git rebase upstream/master

# Fix conflicts, then `git rebase --continue`, repeat until done
# Push to our fork
git push --force origin feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant