git的高级小知识

作者: sunny519111 | 来源:发表于2017-12-21 18:01 被阅读231次

    基础知识

    我们知道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. 分支管理

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

    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 中的提交

    相关文章

      网友评论

      本文标题:git的高级小知识

      本文链接:https://www.haomeiwen.com/subject/kdoawxtx.html