git merge --squash

git merge --squash {srcBranch} 常用于将feat分支合并至dev时压缩繁杂的提交日志,让合并变得清晰明了。

srcBranch上的超前于当前分支的 commits 合并至当前分支,且当前分支不进行commit,合并或解决冲突成功后,允许我们手动做一次 commit log,这样srcBranch的多个 commits 合并至当前分支时只产生一个commit 了。

git checkout devecho 1111 >> foo.txtgit add foo.txtgit commit -m "foo.txt 1111"git checkout -b feat_1echo 2222 >> foo.txt && git commit -am "foo.txt 2222"echo 3333 >> foo.txt && git commit -am "foo.txt 3333"echo 4444 >> foo.txt && git commit -am "foo.txt 4444"git loggit checkout dev# 如果我们直接 git merge feat_1 的话 那 feat_1 的所有提交都会记录至 dev# 但我们想简洁的表征一下git merge --squash feat_1# 手动编写 log 提交git commit -m 'foo.txt 2222foo.txt 3333foo.txt 4444'# 或者使 diff logs 为模板提交git commit -v# 进入 vim 模式 编辑合并的 log:wq# 可以看到 feat_1 的 3 log 合并到 dev 上后只有 1 loggit log

--squash 的作用为只合并源分支的内容到当前分支的stage区,将commit交由我们来决定,这样便可以整合其他分支的提交日志。

git rebase -i

切记不可用于协同开发的分支,只能用于独自使用的分支。

git rebase -i [startPoint] [endPoint]

rebase可以方便我们编辑本分支的commit记录:合并,修改,删除。比如我在feat分支上开发测试ok,需要合并到dev分支,但feat上有很多繁杂的commit logs,我们可能并不需要在dev中体现,可能有人想到可以在dev上使用 merge --squash,但如果feat落后dev 很多,这时我们可能需要使用 git cherry-pick commitLogHash的方法将feat中特定的提交合并至dev分支。这时就需要我们在dev的基础分支上创建一个temp分支,temp merge --squash feat后获得一次性提交的temp_commit_log,然后切换至dev执行 git cherry-pick {temp_commit_log}合并至dev分支,或者我们可以使用 rebase -i HEAD~N HEAD 的方式合并本分支的多次提交。

合并多条提交记录至用一条

git checkout devecho 1111 >> bar.txt && git add bar.txtgit commit -m "bar.txt 1111"git checkout -b feat_2 devecho 2222 >> bar.txt && git commit -am "bar.txt 2222"echo 3333 >> bar.txt && git commit -am "bar.txt 3333"echo 4444 >> bar.txt && git commit -am "bar.txt 4444"# 开发完成 要讲 feat_2 合并回 dev 但不想要太多 feat-2 的 loggit rebase -i dev-----------------------------------------------------------------------pick 0483730 bar.txt 2222pick adf4d92 bar.txt 3333pick cd1b421 bar.txt 4444# Rebase 7ffea48..cd1b421 onto 7ffea48 (3 commands)## Commands:# p, pick <commit> = use commit# r, reword <commit> = use commit, but edit the commit message# e, edit <commit> = use commit, but stop for amending# s, squash <commit> = use commit, but meld into previous commit# f, fixup <commit> = like "squash", but discard this commit's log message# x, exec <command> = run command (the rest of the line) using shell# d, drop <commit> = remove commit# l, label <label> = label current HEAD with a name# t, reset <label> = reset HEAD to a label# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]# .       create a merge commit using the original merge commit's# .       message (or the oneline, if no original merge commit was# .       specified). Use -c <commit> to reword the commit message.## These lines can be re-ordered; they are executed from top to bottom.## If you remove a line here THAT COMMIT WILL BE LOST.-----------------------------------------------------------------------# 修改至如下pick 0483730 bar.txt 2222s adf4d92 bar.txt 3333s cd1b421 bar.txt 4444:wq-----------------------------------------------------------------------# This is a combination of 3 commits.# This is the 1st commit message:# 合并多个日志bar.txt 2222bar.txt 3333bar.txt 4444# 编辑后 :wq 保存退出# Please enter the commit message for your changes. Lines starting# with '#' will be ignored, and an empty message aborts the commit.## Date:      Fri Apr 26 14:26:09 2019 +0800## interactive rebase in progress; onto 7ffea48# Last commands done (3 commands done):#    squash adf4d92 bar.txt 3333#    squash cd1b421 bar.txt 4444# No commands remaining.# You are currently rebasing branch 'feat_2' on '7ffea48'.-----------------------------------------------------------------------# 可以看到三个提交合并至 1 个了git log# 不过会造成 HEAD detached from fed40edgit checkout -b temp# 查看具体的git loggit checkout feat_2git cherry-pick # 切换至 dev 合并 feat_2 的日志会很简洁 git checkout devgit merge feat_2git log

修改 commit log

git rebase -i [startpoint] [endpoint] 的 startpoint 为开区间,所以如我们想修改提交的日志,需要如下

#重建最近一次的提交git rebase -i HEAD~1#重建 HEAD~3 - HEAD~2 的两次提交git rebase -i HEAD~4 HEAD~2

实例,我们对feat_4foo4做了 4 次提交,日志如下

git log --pretty=oneline --abbrev-commitfed40ed (HEAD -> feat_4) foo4 44448455d9a foo4 33331548e84 foo4 222253e837b foo4 1111

重写最近一次提交的日志

git rebase -i HEAD~1#进入交互模式pick fed40ed foo4 4444# Rebase 8455d9a..fed40ed onto 8455d9a (1 command)## Commands:# p, pick <commit> = use commit# r, reword <commit> = use commit, but edit the commit message# e, edit <commit> = use commit, but stop for amending# s, squash <commit> = use commit, but meld into previous commit# f, fixup <commit> = like "squash", but discard this commit's log message# x, exec <command> = run command (the rest of the line) using shell# d, drop <commit> = remove commit# l, label <label> = label current HEAD with a name# t, reset <label> = reset HEAD to a label# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]# .       create a merge commit using the original merge commit's# .       message (or the oneline, if no original merge commit was# .       specified). Use -c <commit> to reword the commit message.------------------------------------------------------------------------------# 修改 pick 为 reword 即保留本次提交,但要对提交信息做编辑pick fed40ed foo4 4444# 保存并退出:wq# 会进入日志编辑模式foo4 4444# Please enter the commit message for your changes. Lines starting# with '#' will be ignored, and an empty message aborts the commit.## Date:      Fri Apr 26 18:40:09 2019 +0800## interactive rebase in progress; onto 8455d9a# Last command done (1 command done):#    reword fed40ed foo4 4444# No commands remaining.# You are currently editing a commit while rebasing branch 'feat_4' on '8455d9a'.## Changes to be committed:#       modified:   foo4--------------------------------------------------------------------------------# 修改至你想要的日志foo4 4444 modify by rebase::reword:wq# 可以看到日志已经被修改git log --pretty=oneline --abbrev-commit7ccdb4c (HEAD -> feat_4) foo4 4444 modify by rebase:reword8455d9a foo4 33331548e84 foo4 222253e837b foo4 1111

git rebase -i合并/修改提交记录的方法如上所示。

git cherry-pick

git cherry-pick的使用场景主要是用于挑选合并某分支上的提交到当前分支。比如我们将feat1合并到了dev,产生了log-dev-feat-1,将feat1合并到了dev,产生了log-dev-feat-2,现在我只想将feat1发布到测试分支,git merge dev已经不能满足了,因为会将log-dev-feat-2一起合并过来。

git checkout devgit merge feat1git merge feat2git log --pertty=onelinegit checkout test# 挑选合并feat1的提交git cherry-pick feat1-log-hash

这样我们就可以灵活的选择要发布到测试环境的功能项了。