基础知识
我们知道 git 一般把区域分为四个部分, 通过不同的命令可以完成每一个区域的切换对于这四种区域, 内心一定要清楚的记住
git.png
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. 分支管理
我们在正式的项目中, 往往是分为以下几个分支
master(主分支)
develop(开发分支)
test(测试分支)
uat(预发布分支)
master 分支应该是非常稳定的, 也就是仅用来发布新版本, 平时不能在上面干活;
那在哪干活呢? 干活都在 dev 分支上, 也就是说, dev 分支是不稳定的, 到某个时候, 比如 1.0 版本发布时, 再把 dev 分支合并到 master 上, 在 master 分支发布 1.0 版本;
你和你的小伙伴们每个人都在 dev 分支上干活, 每个人都有自己的分支, 时不时地往 dev 分支上合并就可以了
修复一个小 bug
已经发布到线上的项目, 老板突然说, 线上这个字写错了, 我们需要立马的修改过来, 停下手里的开发工作, 那应该怎么做呢?
从 develop 切换到 master, 然后拉去远程代码
- git checkout master
- git pull origin master
从 master 开出一个新的分支 bug
git checkout - b bug
然后在 bug 上面修改错误, 修改完成后合并到 master 分支上面
- git checkout master
- git merge bug
完成 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 中的提交
来源: http://www.jianshu.com/p/b6042d9cbc00