1. git commit --amend
有时你提交过代码之后,发现一个地方改错了,
你下次提交时不想保留上一次的记录;
或者你上一次的commit message的描述有误,
这时候你可以使用接下来的这个命令:git commit --amend
该操作会改变你原来的commit id
2. cherry-pick vs rebase vs merge
2.1. merge
那么git merge topic命令将会把在master分支上二者共同的节点
(E节点)之后分离的节点(即topic分支的A B C节点)重现在master分支上,
直到topic分支当前的commit节点(C节点),并位于master分支的顶部。
并且沿着master分支和topic分支创建一个记录
合并结果的新节点,该节点带有用户描述合并变化的信息
2.2. cherry-pick
对于多分支的代码库,将代码从一个分支转移到另一个分支是常见需求。
这时分两种情况。一种情况是,你需要另一个分支的所有代码变动,那么就采用合并(git merge)。
另一种情况是,你只需要部分代码变动(某几个提交),这时可以采用 Cherry pick。
a - b - c - d Master
\
e - f - g Feature
- git cherry-pick 分支
- git cherry-pick
- git cherry-pick
- git cherry-pick A..B
2.3. rebase
概念:git rebase
你其实可以把它理解成是重新设置基线
,将你的当前分支重新设置开始点。这个时候才能知道你当前分支于你需要比较的分支之间的差异。
1. master 1-2-3 是现在的分支状态
2. 这个时候从master ,checkout出来一个prod分支
3. 然后master提交了4.5,prod提交了6.7
4. 这个时候master分支状态就是1-2-3-4-5,prod状态变成1-2-3-6-7
5. 如果在prod上用rebase master ,prod分支状态就成了1-2-3-4-5-6-7
6. 如果是merge 会出来一个8,这个8的提交就是把4-5合进来的提交
好处
:提交直观 便于回退 拉取代码有预处理阶段 不用生成新的节点
注意
:不要通过rebase对任何已经提交到公共仓库中的commit进行修改
- git pull --rebase
- git rebase -i [startpoint] [endpoint]
git rebase [startpoint] [endpoint] --onto [branchName] - git rebase -i HEAD~n
pick:保留该commit(缩写:p)
reword:保留该commit,但我需要修改该commit的注释(缩写:r)
edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)
squash:将该commit和前一个commit合并(缩写:s)
fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)
exec:执行shell命令(缩写:x)
drop:我要丢弃该commit(缩写:d)
3. 什么是 HEAD
3.1 概念:
Git 中的 HEAD
可以理解为一个指针,我们可以在命令行中输入 cat .git/HEAD
查看当前 HEAD
指向哪儿,一般它指向当前工作目录所在分支的最新提交或者分支。
3.2 HEAD游离状态
使用的是 git checkout < commit id>
,即切换到指定的某一次提交,HEAD
就会处于 detached
状态(游离状态)
HEAD 处于游离状态时,我们可以很方便地在历史版本之间互相切换,比如需要回到
某次提交,直接 checkout 对应的 commit id 或者 tag 名即可。
它的弊端就是:在这个基础上的提交会新开一个匿名分支!
可以看到,我还没有修改和提交的情况下,切换完成就给我新建了一个分支,并且指明 HEAD
正游离在 2772886 的 上。
如果不做任何修改,想回到 master 分支,直接 git checkout master 即可,
而不要 checkout master 主干所对应的 。
顺利回到主干的话,HEAD 的游离状态会取消,原临时游离分支也会消失。
如果是在游离状态做了修改和提交,则:
切换会 master 分支时,在游离状态所做的修改和提交无法追溯
3.3 git reset [--soft | --mixed | --hard] HEAD^
-
--mixed
为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。
$ git reset HEAD^ # 回退所有内容到上一个版本
$ git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本
$ git reset 052e # 回退到指定版本
-
--soft
参数用于回退到某个版本 保留工作目录,并把重置 HEAD 所带来的新的差异放进暂存区
什么是「重置 HEAD 所带来的新的差异:
由于 HEAD 从 4 移动了 3,而且在 reset 的过程中工作目录和暂存区的内容没有被清理掉,
所以 4 中的改动在 reset 后就也成了工作目录新增的「工作目录和 HEAD 的差异」。
这就是上面一段中所说的「重置 HEAD 所带来的差异」
-
--hard
参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:
$ git reset –hard HEAD~3 # 回退上上上一个版本
$ git reset –hard bae128 # 回退到某个版本回退点之前的所有信息。
$ git reset --hard origin/master # 将本地的状态回退到和远程的一样
注意:谨慎使用 –hard 参数,它会删除回退点之前的所有信息。
4 Gerrit 的 Change-Id
Change-Id 是 gerrit (代码审核平台)的概念
-
Change-Id
的生成
Gerrit 提供了标准的“commit-msg”钩子来实现。
Git 提供了4个提交工作流钩子:pre-commit、prepare-commit-msg、
commit-msg、post-commit。其中 commit-msg 钩子,
会在我们执行 git commit 时被执行。
本质上,commit-msg 钩子是一段脚本程序,放在 .git/hooks 目录下。
commit-msg 脚本可以使用 Shell、Ruby、Python 等语言实现。
- 案例1
### Squash the commits with the same Change-Id or ensure Change-Ids are unique for each commit
shell
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 4 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 473 bytes | 473.00 KiB/s, done.
Total 5 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4)
remote: Processing changes: refs: 1, done
To ssh://sg-8-130.hst.xxxxx.net:29418/xxxx/xxxxxx
! [remote rejected] HEAD -> refs/for/dev (same Change-Id in multiple changes.
Squash the commits with the same Change-Id or ensure Change-Ids are unique for each commit)
error: failed to push some refs to 'ssh://[email protected]:29418/xxxxx/xxxxx'
在dev分支上有重复的change-id,使用
shell
git commit --amend
- 案例2 缺失
Change-Id
- 如果缺失 Change-Id 的是最后一个 (head) commit, 使用以下命令即可解决问题
$ git commit --amend
- 如果缺失 Change-Id 的不是最后一个 commit,第二个提交缺失 Change-Id, 可用 reset 方法:
$ git reset 1a9096a34322885ac101175ddcac7dab4c52665d
$ git commit --amend
$ git add ......
$ git commit -m "你的提交日志"
$ git push review HEAD:refs/for/dev
- 使用交互式rebase 找回
任意提交位置
的 Change-Id 以及有多个 commit
缺失 Change-Id 的情况
// 找到缺失 Change-Id 的那个 commit:
// 执行 git rebase -i, 参数为 该提交的上一个提交的 commit-id (本例中为 "表单" 那个提交):
$ git rebase -I d714bcde0c14ba4622d28952c4b2a80882b19927
//将缺失了 Change-Id 的 commit 前面的 pick 改为 reword 即可
//逐个编辑 commit-msg 可以不需要修改 保存推出即可
$ git log
commit 8aaaa749db4a5b105aa746659c5cd266ac82fffe
Author: liux
Date: Mon Dec 19 17:43:24 2016 +0800
I am commit message 3
Change-Id: Ic89d5ce6ce4de70d1dcb315ce543c86a2b3ac003
commit 8e1cad33bcd98e175cba710b1eacfd631a5dda41
Author: liux
Date: Mon Dec 19 17:43:00 2016 +0800
I am commit message 2
Change-Id: I9d2af0cc31423cf808cd235de0ad02abf451937d
commit 1a9096a34322885ac101175ddcac7dab4c52665d
Author: liux
Date: Mon Dec 19 15:23:36 2016 +0800
I am commit message 1
commit d714bcde0c14ba4622d28952c4b2a80882b19927
Author: shangsb
Date: Wed Dec 14 09:20:52 2016 +0800
这是一个提交
Change-Id: I629b2bedff95491875f63634ad3da199612735b6
$ git rebase -I d714bcde0c14ba4622d28952c4b2a80882b19927
这个命令会打开默认的编辑器,一般为 vi. 内容如下:
pick 1a9096a I am commit message 1
pick 8e1cad3 I am commit message 2
pick 8aaaa74 I am commit message 3
# Rebase d714bcd..8aaaa74 onto d714bcd
#
# 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
reword 1a9096a I am commit message 1
pick 8e1cad3 I am commit message 2
pick 8aaaa74 I am commit message 3
# Rebase d714bcd..8aaaa74 onto d714bcd
#
# 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
疑问
- A-B-C 应该在最新节点C上追加 假如我想在B或者A上追加应该怎么处理
-
消息分支
已经push 并且已经合并到master-pre 最终合并到master 而我本地追踪的是远程master
但是还是显示超前一个版本 - 错误操作导致我的分支出现别人的代码节点 并且都处于
待push
的状态 也就是超前远程仓库n个版本
参考文档:
https://www.jianshu.com/p/4079284dd970
https://www.jianshu.com/p/4a8f4af4e803