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的高级小知识 #46

Open
huangchucai opened this issue Dec 21, 2017 · 1 comment
Open

git的高级小知识 #46

huangchucai opened this issue Dec 21, 2017 · 1 comment

Comments

@huangchucai
Copy link
Owner

git的高级小知识

基础知识

我们知道git一般把区域分为四个部分,通过不同的命令可以完成每一个区域的切换。对于这四种区域,内心一定要清楚的记住。

git

git add  ..=>  把工作区的内容放入暂存区

git commit .. => 把暂存区的内容提交到本地仓库

git push .. => 把本地仓库推送到远程仓库

版本知识

版本知识

一般HEAD表示当前版本: HEAD^ 表示上一个版本,HEAD^^上上个版本,HEAD~100往上100个版本

当前版本记录

$ git log  //查看当前的版本记录
$ git log --pretty=oneline  // 简化版的查看当前版本记录(省去了时间和本人)
$ git log --pretty=oneline
fea014ebe02b2dde8d88442fd6a2866f0f7b22fc update a
8f06228d024c544796adf6b8796d8b559af4b846 update c.md
77ace164ccc7063270c0268ec15e4f87b01b49a8 create c
3c7280b9cc8144052c2944b1ac9aca10d123de57 create c.md
b14d862114f8214065fdbc97ebc42326889bd607 create b.mc
b66b422aaae32972955216c3ea9d2464dba3473b create a.md
848833db8bbc8f289dfa89610566b20f2a5c5dcd create a.md
e040a733d1c6ffd7eaf26b1f00c0149e3adaf324 测试删除文件
ace6c17bbed2d7bd476d39c1c9b542967f255aa2 提交2.md到本地仓库
a8ae74e2ff0e10fed7dd508eada245b10aba4cd0 提交2.md到本地仓库

历史版本记录

$ git reflog  // 查看历史版本
$ git reflog
fea014e HEAD@{0}: commit: update a
8f06228 HEAD@{1}: reset: moving to HEAD^
a6aed5a HEAD@{2}: commit: update a
8f06228 HEAD@{3}: commit: update c.md
77ace16 HEAD@{4}: commit: create c
3c7280b HEAD@{5}: commit: create c.md
b14d862 HEAD@{6}: commit: create b.mc
b66b422 HEAD@{7}: commit: create a.md
848833d HEAD@{8}: commit: create a.md

1. 检查修改

我们在工作中经常需要对比2个文件的区别,方便我们知道修改的地方。

已修改,未暂存

git diff  <filename>// 工作区和(暂存区,本地仓库)的比较

假如我们现在有一个文件a.md,它里面的内容是This is a, 已经被提交到本地仓库过或者已经存放在暂存区过,现在我们需要给a.md添加字段update a,但是还没有提交到暂存区。通过git diff a.md来判定文件的修改内容。

// a.md
This is a

// 添加字段的a.md
Thid is a
update a
$ git diff a.md
diff --git a/a.md b/a.md
index 483b5ef..dff9281 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 This is a
+update a

已暂存,未提交

git diff --cached <filename>  // 暂存区和本地仓库文件的比较

我们在创建一个b.md,它里面的内容是This is b, 已经被提交过本地仓库一次,现在我们需要给b.md添加字段update b,但是还已经提交到暂存区。通过git diff --cached b.md来判定文件的修改内容。

// b.md
This is b

// 添加字段的b.md 
Thid is b
update b
$ git diff --cached b.md
diff --git a/b.md b/b.md
index 063936b..5eee7b8 100644
--- a/b.md
+++ b/b.md
@@ -1 +1,2 @@
 This is b
+update b

已提交,未推送

git diff master origin/master // 本地仓库和远程仓库的比较

我们在创建一个c.md,它里面的内容是This is c, 已经被提交过远程仓库一次,现在我们需要给c.md添加字段update c,但是还已经提交到本地仓库。通过git diff <branch> <origin/branch>来判定文件的修改内容。

$ git diff master origin/master
diff --git a/c.md b/c.md
index 39b4fb0..5c88cd0 100644
--- a/c.md
+++ b/c.md
@@ -1,2 +1 @@
 This is c
-update c

对比2个版本的指定文件

$ git diff <版本号> <版本号> <文件名> 

我们刚刚创建了一个d.md提交到本地仓库,然后更新了它的内容,也提交到本地仓库,想对比本次提交和上一次提交d.md的内容差别。

// 1. 查看我们刚刚提交的版本记录
$ git log --pretty=oneline
fbecc1386e8d1d2bdad26ab65d0a0650f14f7206 update d.md
f4001ea7c5cc5809c03f6b6b15dff616cbf4dc4a create d.md
8f06228d024c544796adf6b8796d8b559af4b846 update c.md

// 2. 对比f4001ea和fbecc13的区别
$ git diff f4001ea fbecc13 d.md
diff --git a/d.md b/d.md
new file mode 100644
index 0000000..fd25f48
--- /dev/null
+++ b/d.md
@@ -0,0 +1,2 @@
+This is d
+update d

// 可以很明显的看出,我们添加了2行代码
// 我们再更新下
$ git reflog
5987f16 HEAD@{0}: commit: 第二次更新d.md
fbecc13 HEAD@{1}: commit: update d.md
f4001ea HEAD@{2}: commit: create d.md

// 2. 对比fbecc13和5987f16的区别
$ git diff fbecc13 5987f16 d.md
diff --git a/d.md b/d.md
index fd25f48..b6f7a8f 100644
--- a/d.md
+++ b/d.md
@@ -1,2 +1,3 @@
 This is d
 update d
+update d2
总结:

git diff <filename> 工作区和(暂存区,本地仓库)的比较

git diff --cached <filename> 暂存区和本地仓库的比较

git diff <branch> <origin/branch> 本地仓库和远程仓库的比较

$ git diff <版本号> <版本号> <文件名> 对比不同版本的文件


2. 撤销修改

人生谁不犯一点错误,但是git给我们修改错误的机会,这样就可以让你的年终奖不至于因为你的疏忽而没有。

已修改,未暂存

git checkout -- <file>  // 不要忘记了整个 --  
git checkout .  

我们已经有一个a.md,它里面的内容是This is a, 我们无意中添加了add 1这样的字段,但是又没有用处,想撤销添加的add 1,并且还没有放入暂存区

// a.md 
This is a
+ add 1  // 想撤销添加的字段
// 1. 没有撤销之前
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   a.md

no changes added to commit (use "git add" and/or "git commit -a")

// 2. 撤销
$ git checkout -- a.md

//3. 撤销之后
$ git status
On branch master
nothing to commit, working tree clean

已暂存,未提交

git reset HEAD <file> // 把暂存区的内容退回工作区
git checkout -- <file>  

我们已经有一个a.md,它里面的内容是This is a, 我们无意中添加了add 2这样的字段,但是又没有用处,想撤销添加的add 1,并且还已经放入暂存区

// 1. 没有撤销之前
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   a.md

// 2. 撤回到工作区
$ git reset HEAD a.md
Unstaged changes after reset:
M       a.md

// 3. 已经回到工作区
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   a.md

no changes added to commit (use "git add" and/or "git commit -a")

// 4. 撤销工作区
$ git checkout -- a.md

已提交,未推送

$ git reset --hard HEAD^  //回退到本地仓库的上一个版本  

我们已经有一个a.md,它里面的内容是This is a, 我们无意中添加了add 3这样的字段,但是又没有用处,想撤销添加的add 1,并且还已经提交到本地仓库了

// 1. 已经提交
$ git commit -am 'update a'
[master 2f04a8e] update a
 1 file changed, 2 insertions(+), 1 deletion(-)

// 2. 撤销已经提交的
$ git reset --hard HEAD^
HEAD is now at fea014e update a

撤销到指定版本

// 1. 通过历史记录,查到你想要倒退到哪一个版本
$ git log 

// 2. 通过撤销
$ git reset --hard '版本号'
// 1. 
$ git log
commit fea014ebe02b2dde8d88442fd6a2866f0f7b22fc
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 10:11:20 2017 +0800

    update a

commit 8f06228d024c544796adf6b8796d8b559af4b846
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:12:27 2017 +0800

    update c.md

commit 77ace164ccc7063270c0268ec15e4f87b01b49a8
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:11:42 2017 +0800

    create c

commit 3c7280b9cc8144052c2944b1ac9aca10d123de57
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:07:25 2017 +0800

    create c.md
//2. 倒退到 create c.md
$ git reset --hard 3c7280b

// 3. 再次查看当前版本记录,就会发现之前的版本都没有了,最新的也是3c7280b的create c.md
commit 3c7280b9cc8144052c2944b1ac9aca10d123de57
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:07:25 2017 +0800

    create c.md

commit b14d862114f8214065fdbc97ebc42326889bd607
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 17:51:03 2017 +0800

    create b.mc

commit b66b422aaae32972955216c3ea9d2464dba3473b
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 17:43:08 2017 +0800

    create a.md

撤销到指定版本后,还想回到之前的某一个版本

我刚刚撤销到c.md后后悔了,应该倒退到它的上2个版本的,现在怎么办呢?通过git log又查询不到,愁死我了,这个时候救命天子git reflog登上历史舞台。

// 查看全部历史记录
$ git reflog
3c7280b HEAD@{0}: reset: moving to 3c7280b
fea014e HEAD@{1}: reset: moving to HEAD^
2f04a8e HEAD@{2}: commit: update a
fea014e HEAD@{3}: commit: update a
8f06228 HEAD@{4}: reset: moving to HEAD^
a6aed5a HEAD@{5}: commit: update a
8f06228 HEAD@{6}: commit: update c.md
77ace16 HEAD@{7}: commit: create c
3c7280b HEAD@{8}: commit: create c.md

上面的记录清晰的告诉我们,我们刚刚退回到了3c7280b,也可以看到它的上2个版本是8f06228 update c.md

// 1. 退回到8f06228版本
$ git reset --hard 8f06228

// 2. 查看当前版本记录
$ git log
commit 8f06228d024c544796adf6b8796d8b559af4b846
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:12:27 2017 +0800

    update c.md

commit 77ace164ccc7063270c0268ec15e4f87b01b49a8
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:11:42 2017 +0800

    create c

commit 3c7280b9cc8144052c2944b1ac9aca10d123de57
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 18:07:25 2017 +0800

    create c.md

commit b14d862114f8214065fdbc97ebc42326889bd607
Author: sunny <sunny@lianj.com>
Date:   Wed Dec 20 17:51:03 2017 +0800

    create b.mc

3. 合并多条commit

$ git rebase -i <版本号>  //  $ git rebase -i HEAD~i  
// reabse squash     rebase fixup

-i 实际上就是 --interactive 的简写,在使用 git rebase -i 时,我们要在后面再添加一个参数,这个参数应该是 最新的一个想保留的 Commit,就是不会合并的commit。

有的时候开发项目的一个小功能,我们没完成一部分都会git commit,等到工程完成后,就会出现很多commit,这样不方便管理和查看功能,怎么才能合并多个commit呢?

// 1. 查看提交记录
$ git log
commit b921d5f230b4bfb54307371cca8b15afcdd38236
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:15:18 2017 +0800

    commit 3

commit 649eb33de6cb5592bbb9a659cf3c44bdc324317f
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:14:55 2017 +0800

    commit 2

commit ee0e1b28c328792096e4dfea599d38374ce6a480
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:00:04 2017 +0800

    commit 1
// 2.现在合并commit2 和 commit 3 , 从commit 1 开始
$ git reabse -i HEAD~2 // 进入交互页面
// 3. 从下面可以看出我们可以用到s(squash)  
pick 649eb33 commit 2
pick b921d5f commit 3

# Rebase ee0e1b2..b921d5f onto ee0e1b2 (2 commands)
#
# 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
# d, drop = remove commit

// 4. 把commit 3 pick改成 s 就相当于把commit 2 放入commit 3中的前面
pick 649eb33 commit 2
s b921d5f commit 3
// 5. 你会进入一个新的commit 界面 :wq退出
// 6. 再次查看log
$ git log
commit b646746055840c1f98de3bbf498d8ef8f26117e3
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:14:55 2017 +0800

    commit 2

    commit 3

commit ee0e1b28c328792096e4dfea599d38374ce6a480
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:00:04 2017 +0800

    commit 1

可能会遇到的问题

人生都不是一帆风顺的,在你合并的时候可能会遇到一些问题,例如下面的:

我们在把之前的合并退回来

// 1. 看看目前的状态
$ git status
On branch master
nothing to commit, working tree clean

// 2. 用我们之前的回退到上一个版本
$ git reset HEAD^
  
// 3. 回退完后
$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   a.js

no changes added to commit (use "git add" and/or "git commit -a")

// 4. 在处理成开始的样子,有三个提交记录commit 1  commit 2 commit 3
// 5. 再次进入的时候我们把commit 2 的pick改为s
pick 649eb33 commit 2
pick b921d5f commit 3
// 6
s 649eb33 commit 2
pick b921d5f commit 3
//7. 就会出问题了,我们来看看问题的本源
$ git rebase -i ee0e1b
error: cannot 'squash' without a previous commit
You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
Or you can abort the rebase with 'git rebase --abort'.

看提示是without a previous commit 没有一个先前的提交,我们使用s的时候和合并到先前的提交,而我们进入交互模式-i的时候,commit 2之前确实没有可以插入的commit

// commit 2之前没可以插入的commit
# s, squash = use commit, but meld into previous commit
s 649eb33 commit 2
pick b921d5f commit 3

解决

$ git rebase --abort // 取消本次的合并,重新来

测试

我们测试一下我们的猜想正不正确?

// 1. 有四个commit 
$  git log
commit 37fcf0211672026db25d43b25bc1ca76f2877615
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:59:23 2017 +0800

    commit 4

commit 0efdd45062fabb687633b195f7866fc2b16c2e03
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:37:19 2017 +0800

    commit 3

commit deeece14b4444fde6bbcb4584017ac3e13757d6e
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:36:44 2017 +0800

    commit 2

commit ee0e1b28c328792096e4dfea599d38374ce6a480
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:00:04 2017 +0800

    commit 1

// 2. 合并commit 1 前面的三个
$ git rebase -i ee0e1b
// 3. 进入交互页面,把commit 3 和 commit 4 改为 s
pick deeece1 commit 2
s 0efdd45 commit 3
s 37fcf02 commit 4

// 4. 修改完成后
$ git log
commit 00b478bfae42ce72e8080aa8bc0127a956a0f800
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:36:44 2017 +0800

    commit 2

    commit 3

    commit 4

commit ee0e1b28c328792096e4dfea599d38374ce6a480
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:00:04 2017 +0800

    commit 1

4. 分支管理

我们在正式的项目中,往往是分为以下几个分支

  1. master(主分支)
  2. develop(开发分支)
  3. test(测试分支)
  4. uat(预发布分支)

master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

修复一个小bug

已经发布到线上的项目,老板突然说,线上这个字写错了,我们需要立马的修改过来,停下手里的开发工作,那应该怎么做呢?

  1. 从develop切换到master,然后拉去远程代码

    git checkout master
    git pull origin master
  2. 从master开出一个新的分支bug

    git checkout -b bug
  3. 然后在bug上面修改错误,修改完成后合并到master分支上面

    git checkout master
    git merge bug
  4. 完成bug后删除开的分支

    git branch -d bug

5. 修改commit的内容

修改最新的一条commit

$ git commit --amend

修改其他的commit

// 1. 查看历史
$ git log
commit fc8e6d60941d5408f7b37d6b1e7ce61311cff8dd
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 17:25:31 2017 +0800

    commit 5

commit 922a1b9f8e3136da34fef2f2d05ca42e2cf1c730
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:36:44 2017 +0800

    commit 2

    commit 3

    commit 4

commit ee0e1b28c328792096e4dfea599d38374ce6a480
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:00:04 2017 +0800

    commit 1

// 2. 通过rebase回到我们要修改的commit 
$ git rebase -i ee0e1b

// 3. 进入交互模式,把对应的commit 的pick改为e
e 922a1b9 commit 2
pick fc8e6d6 commit 5

// 4. 然后进入了对于的基层
$ git commit --amend
[detached HEAD 2d45119] commit 2 修改了的 commit 3
 Date: Thu Dec 21 16:36:44 2017 +0800
 4 files changed, 3 insertions(+)
 create mode 100644 b.js
 create mode 100644 c.js
 create mode 100644 m.nmd

// 5. 修改完成
$ git rebase --continue
Successfully rebased and updated refs/heads/master.

// 6. c查看历史
$ git log
commit 3fb44dac394983a26e6790e46934c37fe00ac4af
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 17:25:31 2017 +0800

    commit 5

commit 2d4511915ad46ff5e8809f14a29e5c47ff5e1e44
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:36:44 2017 +0800

    commit 2
    修改了的
    commit 3

    commit 4

commit ee0e1b28c328792096e4dfea599d38374ce6a480
Author: sunny <sunny@lianj.com>
Date:   Thu Dec 21 16:00:04 2017 +0800

    commit 1

6. git cherry-pick(也很重要)

$ git cherry-pick  // 把对应的commit 复制到其他的分支
参考链接(篇幅有限,但是很重要)

Git笔记(三)——[cherry-pick, merge, rebase]

7. git小知识

$ gitk // 可以调用出git的图形操作界面

参考链接

git如何修改已提交的commit

如何优雅地合并多个 Commit

廖雪峰的git教程

如何彻底删除 Git 中的提交

@stephen-a2z
Copy link

gitk 我这里无法使用
bash: gitk: command not found

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

2 participants