编程不止是一份工作,还是一种乐趣!!!
前前后后看了Git好多遍,一段时间不用又忘了,年纪大了记性不好,还是写点笔记^_^
在Git中,HEAD指向当前分支的最近一次commit。而git reset命令的作用就是重置HEAD到另外一个commit。
git reset --hard HEAD^ 撤销HEAD、index与working copy
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
f141537 (HEAD -> master) 3c
3e1d16d 2c
3c21b03 1c
Liangs-MacBook-Pro:test john$ git reset --hard HEAD^
HEAD is now at 3e1d16d 2c
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
3e1d16d (HEAD -> master) 2c
3c21b03 1c
Liangs-MacBook-Pro:test john$ git status -s
Liangs-MacBook-Pro:test john$
从输出可以看到,带–hard参数的撤销,会覆盖HEAD、index与working copy三个区域,是个非常危险的操作。
git reset --soft HEAD^ 只撤销HEAD
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
f141537 (HEAD -> master) 3c
3e1d16d 2c
3c21b03 1c
Liangs-MacBook-Pro:test john$ git reset --soft HEAD^
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
3e1d16d (HEAD -> master) 2c
3c21b03 1c
Liangs-MacBook-Pro:test john$ git status -s
M file.txt
Liangs-MacBook-Pro:test john$
从输出可以看到,带–soft参数的撤销,只会覆盖HEAD,index与working copy保持不变。
git reset --mixed HEAD^ 撤销HEAD与index
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
f141537 (HEAD -> master) 3c
3e1d16d 2c
3c21b03 1c
Liangs-MacBook-Pro:test john$ git reset --mixed HEAD^
Unstaged changes after reset:
M file.txt
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
3e1d16d (HEAD -> master) 2c
3c21b03 1c
Liangs-MacBook-Pro:test john$ git status -s
M file.txt
Liangs-MacBook-Pro:test john$
从输出可以看到,带–mixed参数(默认)的撤销,会覆盖HEAD与index,但working copy保持不变。
Liangs-MacBook-Pro:test john$ cat file.txt
1
2
3
Liangs-MacBook-Pro:test john$ echo "4" >> file.txt
Liangs-MacBook-Pro:test john$ git add file.txt
Liangs-MacBook-Pro:test john$ echo "5" >> file.txt
Liangs-MacBook-Pro:test john$ git status -s
MM file.txt
Liangs-MacBook-Pro:test john$
文件file.txt在HEAD中的值是123,在index中是1234,在working copy中是12345。
git diff file.txt 比较working copy与index中的差异
Liangs-MacBook-Pro:test john$ git diff file.txt
diff --git a/file.txt b/file.txt
index 94ebaf9..8a1218a 100644
--- a/file.txt
+++ b/file.txt
@@ -2,3 +2,4 @@
2
3
4
+5
Liangs-MacBook-Pro:test john$
git diff --cached file.txt 比较HEAD与index中的差异
Liangs-MacBook-Pro:test john$ git diff --cached file.txt
diff --git a/file.txt b/file.txt
index 01e79c3..94ebaf9 100644
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,4 @@
1
2
3
+4
Liangs-MacBook-Pro:test john$
git diff HEAD file.txt 比较HEAD与working copy中的差异
Liangs-MacBook-Pro:test john$ git diff HEAD file.txt
diff --git a/file.txt b/file.txt
index 01e79c3..8a1218a 100644
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,5 @@
1
2
3
+4
+5
Liangs-MacBook-Pro:test john$
在开发过程中,一般的场景是这样的:当完成需要的开发时,我们会进行一次commit,提交给QA人员测试。当发现bug时,我们会对代码进行修改,然后再次提交。最终测试通过后,我们会把开发分支合并到master分支,然后上线。
这个过程本身没什么,但是对于强迫症患者来说,代码的提交记录会很难看,feature和bug fix的记录会穿插在一起,比如:
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
018e112 (HEAD -> master) fix another bug
1834e4c fix a bug
b403d1f complete requirement
663b76f initial commit
通过git rebase命令,我们可以把b403d1f、1834e4c、018e112这三个commit合并成一个commit。
由于我们要合并的是近三个commit提交记录,可以使用git rebase -i HEAD~3,输入命令后进入一个交互页,如下:
pick b403d1f complete requirement
pick 1834e4c fix a bug
pick 018e112 fix another bug
# Rebase 663b76f..018e112 onto 663b76f (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.
#
# However, if you remove everything, the rebase will be aborted.
#
#
# Note that empty commits are commented out
下面注释的部分是说明,要把三个commit合并成一个,我们只需要把前三行的commit改为下面这样:
r b403d1f complete requirement
f 1834e4c fix a bug
f 018e112 fix another bug
之后会弹出另一个页面,让我们输入合并后的commit message
complete requirement with bug fixed.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Nov 13 20:54:35 2018 +0800
#
# interactive rebase in progress; onto 663b76f
# Last command done (1 command done):
# reword b403d1f complete requirement
# Next commands to do (2 remaining commands):
# fixup 1834e4c fix a bug
# fixup 018e112 fix another bug
# You are currently editing a commit while rebasing branch 'master' on '663b76f'
#
# Changes to be committed:
# modified: file.txt
#
输入好新的commit message之后退出,就算合并完成,现在我们再用git log看看commit历史,原来的4条commit记录已经变成了2条。
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit
a9b48f6 (HEAD -> master) complete requirement with bug fixed.
663b76f initial commit
当同一个文件在多个分支都被修改了,合并时有可能产生冲突,像下面这样:
Liangs-MacBook-Pro:test john$ git checkout -b newbranch
Switched to a new branch 'newbranch'
Liangs-MacBook-Pro:test john$ echo 'new line added in newbranch' >> file.txt
Liangs-MacBook-Pro:test john$ git add file.txt
Liangs-MacBook-Pro:test john$ git commit -m 'add a line in newbranch'
[newbranch f1517f7] add a line in newbranch
1 file changed, 1 insertion(+)
Liangs-MacBook-Pro:test john$ git checkout master
Switched to branch 'master'
Liangs-MacBook-Pro:test john$ echo 'new line added in master' >> file.txt
Liangs-MacBook-Pro:test john$ git add file.txt
Liangs-MacBook-Pro:test john$ git commit -m 'add a line in master'
[master 7a09676] add a line in master
1 file changed, 1 insertion(+)
Liangs-MacBook-Pro:test john$ git merge newbranch
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
Liangs-MacBook-Pro:test john$
从输出中看出明确的看到file.txt文件在合并时产生了冲容,可以使用git status查询更多的信息:
Liangs-MacBook-Pro:test john$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: file.txt
no changes added to commit (use "git add" and/or "git commit -a")
Liangs-MacBook-Pro:test john$
both modified: file.txt
告诉我们两个分支都对文件进行了修改。可以使用命令git merge --abort取消这次合并,或者手动解决冲突。我们看一下文件的内容:
Liangs-MacBook-Pro:test john$ cat file.txt
initial content
<<<<<<< HEAD
new line added in master
=======
new line added in newbranch
>>>>>>> newbranch
Liangs-MacBook-Pro:test john$
作为示例,我们简单的保留两个分支上的内容,然后通过一次commit解决冲突:
Liangs-MacBook-Pro:test john$ vim file.txt
Liangs-MacBook-Pro:test john$ cat file.txt
initial content
new line added in master
new line added in newbranch
Liangs-MacBook-Pro:test john$ git add file.txt
Liangs-MacBook-Pro:test john$ git commit -m 'fix conflict'
[master 0ef06b9] fix conflict
Liangs-MacBook-Pro:test john$ git log --pretty=oneline --abbrev-commit --graph
* 0ef06b9 (HEAD -> master) fix conflict
|\
| * f1517f7 (newbranch) add a line in newbranch
* | 7a09676 add a line in master
|/
* e00a6eb initial commit
通过带参数的git log命令可以很直观的看到分支的合并情况。