美文网首页DevSupportdocker&Jkenkis&mavenGit
看完不会Git命令行我跪搓板

看完不会Git命令行我跪搓板

作者: 付凯强 | 来源:发表于2018-09-18 15:09 被阅读496次

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

    0. 序言

    之前不太重视Git的命令行操作,直到去了前些天一直炒的非常火的某某某某公司,呆了几天帮忙解BUG,发现项目不用AndroidStudio的图形化界面操作版本控制,一时间傻眼......想到应该也有小伙伴和我一样,所以就有了这篇文章,希望通过阅读这篇文章大家都能学会Git命令行操作。
    讲述方式非面面俱到。喜欢后者的,可以买本书细细品。讲解目录如下:

    • 简介
    • Git的完整性
    • Git的文件状态和工作区域
    • 用户身份
    • 编辑器
    • 创建本地仓库
    • 常用本地操作
    • 版本回退
    • 撤销修改
    • 删除相关操作
    • 远程仓库
    • 分支
    • 解决冲突
    • 变基

    1. 简介

    Git 是分布式版本控制系统,客户端保留完整的代码仓库,就算搭载远程仓库的服务器出了故障,客户端的数据也可以用来恢复服务器数据。
    Git 操作几乎都在本地完成,速度快,效率高,且不受网络限制。

    2. Git的完整性

    Git以校验和的方式检测数据的完整性。采用的校验和机制叫做SHA-1散列。SHA-1散列由40个十六进制字符(0-9和a-f)所组成的字符串,这些字符串是根据文件内容和Git的目录结构计算所得。在Git中commit id 就是校验和,如下:

    $git log
    commit 555af4a0aadb6c64a73acfd94c8fe89af5604083
    Author: Fu Kaiqiang <fukaiqiang@xxx.com>
    Date:   Mon Sep 17 10:45:24 2018 +0800
    
        first commit
    

    3. Git的文件状态和工作区域

    • 工作区域:
      ① 工作目录:平时写代码的区域。
      ② 暂存区:代码add以后commit之前所在的地方。
      ③ 本地仓库:代码commit以后所在的地方。
    • 文件状态:
      ① 已修改:工作目录修改以后,代码没有add到暂存区,也没有commit到本地仓库。
      ② 已暂存:工作目录修改以后,代码已经add到暂存区,没有commit到本地仓库。
      ③ 已提交:工作目录修改以后,代码已经commit到本地仓库。

    3. 用户身份

    • 配置个人信息
    $ git config --global user.name "Your Name"
    $ git config --global user.email "email@example.com"
    

    说明:--global 表示你这台机器上所有的Git仓库都会使用这个配置

    • 查看个人信息
    $git config --list
    user.email=fukaiqiang@xxx.com
    user.name=Fu Kaiqiang
    alias.st=status
    alias.co=checkout
    alias.dt=difftool -t meld -y
    color.ui=auto
    core.repositoryformatversion=0
    core.filemode=true
    core.bare=false
    core.logallrefupdates=true
    remote.origin.url=git@github.com:OnlyYouMyLove/TestGit.git
    remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
    branch.master.remote=origin
    branch.master.merge=refs/heads/master
    

    4. 编辑器

    • 不同操作系统推荐使用不同编辑器,Linux推荐使用Vim,Window可使用NotePad++
    以vim为例:
    vim TestGit.md
    

    说明:vim 可以创建并打开TestGit.md文件。不是重点,不详述,感兴趣,可找小度或小谷。

    5. 创建本地仓库

    • 初始化本地仓库
    - $ git init  
    

    说明:初始化仓库,生成 .git 文件即可

    • 克隆远程仓库到本地
    $git clone git@github.com:OnlyYouMyLove/TestGit.git
    Cloning into 'TestGit'...
    remote: Counting objects: 6, done.
    remote: Compressing objects: 100% (4/4), done.
    remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
    Receiving objects: 100% (6/6), 4.76 KiB | 0 bytes/s, done.
    Checking connectivity... done.
    

    说明:
    ① 初始化仓库和克隆远程仓库是创建本地仓库两种方式,根据场景不同,选择不同的创建方式。
    ② 本地仓库初始化以后,还需要和远程仓库进行关联,远程仓库部分讲。

    6. 常用本地操作

    • 添加文件到暂存区
    $ git add readme.txt
    
    • 把暂存区的文件提交到本地仓库
    $ git commit -m "wrote a readme file"
    

    说明: -m后添加此次提交的说明

    • 跳过暂存区执行提交
    $git commit -a -m "skip stage to commit"
    On branch master
    Your branch is ahead of 'origin/master' by 3 commits.
      (use "git push" to publish your local commits)
    nothing to commit, working directory clean
    

    说明:-a 参数可以自动暂存文件,然后执行提交。

    • 查看本地仓库提交历史
    $git log
    commit 462a66ec484df873bc5638fbd53523408ecfed43
    Merge: 34a6e3f 44d733a
    Author: Fu Kaiqiang <fukaiqiang@xxx.com>
    Date:   Fri Sep 14 10:28:10 2018 +0800
    
        Merge remote-tracking branch 'origin/master'
    
    commit 34a6e3f6dba34d4870da3f9a25ab653a33ae2a49
    Author: Fu Kaiqiang <fukaiqiang@xxx.com>
    Date:   Fri Sep 14 10:21:42 2018 +0800
    
        Today is Friday!
    
    • 简洁的方式查看本地仓库提交历史
    $git log --pretty=oneline
    462a66ec484df873bc5638fbd53523408ecfed43 Merge remote-tracking branch 'origin/master'
    34a6e3f6dba34d4870da3f9a25ab653a33ae2a49 Today is Friday!
    
    • 查看文件状态
    $git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    Changes to be committed:         
      (use "git reset HEAD <file>..." to unstage)  
    
        modified:   TestGit.md
    
    Untracked files: 
      (use "git add <file>..." to include in what will be committed)
    
        .TestGit.md.swo
        .TestGit.md.swp
    
    

    说明:
    ① Changes to be committed:已暂存、可提交文件
    ② Untracked files:未暂存文件

    • 查看未暂存文件变更细节
    $git diff
    diff --git a/TestGit.md b/TestGit.md
    index 1de64fb..89aaf06 100644
    --- a/TestGit.md
    +++ b/TestGit.md
    @@ -1,2 +1,3 @@
     Hello World 
     Hello Chuizi
    +Hello Branch
    
    • 查看已暂存文件变更细节
    $git diff --staged
    diff --git a/TestGit.md b/TestGit.md
    index bc8bff8..2d675a0 100644
    --- a/TestGit.md
    +++ b/TestGit.md
    @@ -2,3 +2,4 @@ Hello World
     Hello Chuizi
     Hello HUAWEI
     Hello XIAOMI
    +Hello MEIZU
    

    说明:文件一旦暂存,通过git diff命令就不能查询差异,必须添加--staged参数,或--cached参数。

    7. 版本回退

    • 回退到上一个版本
    文件内容:
      1 Hello World
      2 Test Git
      3 Hello ChuiZi
      4 Hello JianGuo
      5 hahahahah
      6 fdafafafafaf
      7 fajfkajfakdjfk
      8 eight line
      9 nine line
     10 tenth line
    
    $git log
    commit c836aafa9e33890aebd9b53c816e3180ccd4ddb7
    Author: Fu Kaiqiang <fukaiqiang@smartisan.com>
    Date:   Fri Sep 14 17:01:59 2018 +0800
    
        add tenth line
    
    commit b1a66343568506fdb9960ebd3d896fd798ac61a4
    Author: Fu Kaiqiang <fukaiqiang@smartisan.com>
    Date:   Fri Sep 14 17:01:09 2018 +0800
    
        add ninth line
    
    $git reset --hard HEAD^
    HEAD is now at b1a6634 add ninth line
    

    说明:以上这句命令行代码是核心代码

    $git log
    commit b1a66343568506fdb9960ebd3d896fd798ac61a4
    Author: Fu Kaiqiang <fukaiqiang@smartisan.com>
    Date:   Fri Sep 14 17:01:09 2018 +0800
    
        add ninth line
    
    文件内容:
      1 Hello World
      2 Test Git
      3 Hello ChuiZi
      4 Hello JianGuo
      5 hahahahah
      6 fdafafafafaf
      7 fajfkajfakdjfk
      8 eight line
      9 nine line
    
    • 查询每次版本提交记录
    $git reflog
    c836aaf HEAD@{0}: reset: moving to c836a
    b1a6634 HEAD@{1}: reset: moving to HEAD^
    c836aaf HEAD@{2}: commit: add tenth line
    b1a6634 HEAD@{3}: commit: add ninth line
    

    说明:内容包括 ① commit id ② 执行的命令 ③ 描述

    • 回退到指定版本
    $git reset --hard c836a
    HEAD is now at c836aaf add tenth line
    

    说明:
    ① 找到commit id,就可以回退到指定版本。
    ② commit id 不用填全部,填写部分,git 自动查找。

    • 查看工作区和版本库里面最新版本的区别
    修改TestGit.md内容为:
    Hello World
    
    $git add TestGit.md 
    
    再修改TestGit.md内容为:
    Hello World
    Hello Chuizi
    
    $git commit -m "Two line"
    [master 7dd7cf8] Two line
     1 file changed, 1 insertion(+), 11 deletions(-)
    
    $git status
    On branch master
    Your branch is ahead of 'origin/master' by 1 commit.
      (use "git push" to publish your local commits)
    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:   TestGit.md
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    说明:这时发现还有未添加到暂存区的内容。

    $git diff HEAD -- TestGit.md
    diff --git a/TestGit.md b/TestGit.md
    index 35eab83..1de64fb 100644
    --- a/TestGit.md
    +++ b/TestGit.md
    @@ -1,2 +1,2 @@
     Hello World 
    -
    +Hello Chuizi
    

    说明:
    ① 发现第二次修改没有提交到暂存区,导致 git commit 提交的只是第一次的修改。
    ② git diff 命令是核心代码。
    ③ 这个时候再执行一遍add和commit操作即可。

    8. 撤销修改

    • 撤销未添加到暂存区的修改
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is up to date with 'origin/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:   TestGit.md
    
    no changes added to commit (use "git add" and/or "git commit -a")
    

    说明:discard changes - 放弃修改:的提示为 "git checkout -- <file>..."

    fukqdembp:TestGit fukq$ git checkout -- TestGit.md
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is up to date with 'origin/master'.
    
    nothing to commit, working tree clean
    
    • 撤销已添加到暂存区的修改:
    fukqdembp:TestGit fukq$ git add TestGit.md
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is up to date with 'origin/master'.
    
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
        modified:   TestGit.md
    

    说明:to unstage - 不暂存的提示为 "git reset HEAD <file>..."

    fukqdembp:TestGit fukq$ git reset HEAD TestGit.md
    Unstaged changes after reset:
    M   TestGit.md
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is up to date with 'origin/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:   TestGit.md
    
    no changes added to commit (use "git add" and/or "git commit -a")
    fukqdembp:TestGit fukq$
    

    9. 删除相关操作

    • 删除文件后的Git同步操作
    fukqdembp:TestGit fukq$ ls
    LICENSE     README.md   TestGit.md  TestGit.txt
    
    fukqdembp:TestGit fukq$ rm TestGit.txt
    
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is ahead of 'origin/master' by 1 commit.
      (use "git push" to publish your local commits)
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
        deleted:    TestGit.txt
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    fukqdembp:TestGit fukq$ git rm TestGit.txt
    rm 'TestGit.txt'
    
    fukqdembp:TestGit fukq$ git commit TestGit.txt -m "删除TestGit.txt文件"
    [master 7075b5f] 删除TestGit.txt文件
     1 file changed, 1 deletion(-)
     delete mode 100644 TestGit.txt
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is ahead of 'origin/master' by 2 commits.
      (use "git push" to publish your local commits)
    
    nothing to commit, working tree clean
    
    fukqdembp:TestGit fukq$ ls
    LICENSE     README.md   TestGit.md
    

    说明:
    ① rm TestGit.txt
    ② git rm TestGit.txt
    ③ git commit TestGit.txt -m "删除TestGit.txt文件"

    • 删除文件后的恢复文件操作
    fukqdembp:TestGit fukq$ rm TestGit.txt
    
    fukqdembp:TestGit fukq$ git status
    On branch master
    Your branch is ahead of 'origin/master' by 3 commits.
      (use "git push" to publish your local commits)
    
    Changes not staged for commit:
      (use "git add/rm <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
        deleted:    TestGit.txt
    
    no changes added to commit (use "git add" and/or "git commit -a")
    
    fukqdembp:TestGit fukq$ git checkout -- TestGit.txt
    
    fukqdembp:TestGit fukq$ ls
    LICENSE     README.md   TestGit.md  TestGit.txt
    

    说明:$ git checkout --TestGit.txt 既可以对未添加到暂存区的修改操作进行恢复,也可以对已删除的文件进行恢复。

    10. 远程仓库

    • 关联远程仓库
    $git remote add origin git@github.com:OnlyYouMyLove/TestGit.git
    

    说明:
    ① 组成 -- git remote add + 自定义仓库命名 + 仓库ssh地址
    ② git init 初始化仓库以后需要进行 git remote操作,实现本地和远程仓库的绑定,这才能算是完整创建本地仓库。

    • 第一次推送本地仓库内容到远程仓库
    $git push -u origin master
    

    说明:
    ① -u 参数的添加可以让本地仓库和远程仓库进行绑定
    ② 如果报以下错,意思是缺少权限--本地生成ssh,添加到github的ssh列表即可:

    $git push -u origin master
    Warning: Permanently added the RSA host key for IP address 'xxx.xx.xxx.xxx' to the list of known hosts.
    Permission denied (publickey).
    fatal: Could not read from remote repository.
    
    Please make sure you have the correct access rights
    and the repository exists.
    

    ③ 如果报以下错,输入yes即可:

    The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
    RSA key fingerprint is xx.xx.xx.xx.xx.
    Are you sure you want to continue connecting (yes/no)?
    
    Warning: Permanently added 'github.com' (RSA) to the list of known hosts.
    

    说明:警告只会出现一次。
    ④ 查看ssh key (linux系统下,其他系统大同小异):

    $cat ~/.ssh/id_rsa.pub
    
    • 非第一次推送本地仓库内容到远程仓库
    $git push origin master
    
    • 从远程仓库拉取数据到本地
    $git fetch origin
    

    说明:
    ① git clone 自动命名远程仓库服务器名字为origin,并拉取全部数据,然后在本地创建指向服务器上master分支的指针,并命名为origin/master,它就叫远程分支,接着git会创建本地master分支。
    ② fetch 这条命令会从服务器取得所有本地尚未包含的数据,然后更新远程分支。注意:只是更新远程分支,本地master分支并未改变,需要合并才行。
    ③ origin 与 master分支名称一样,只是默认名称,没有什么特殊含义,都可以自定义。

    $git merge origin/master
    Updating ce50a7f..253d867
    Fast-forward
     TestGit.md | 1 +
     1 file changed, 1 insertion(+)
    

    说明:只要经过fetch和merge才能把远程仓库的数据同步给本地仓库。

    • 从远程仓库拉取数据并直接合并到本地
    $git pull origin master
    From github.com:OnlyYouMyLove/TestGit
     * branch            master     -> FETCH_HEAD
    Updating ce50a7f..5ec3b49
    Fast-forward
     .test.swp  | Bin 0 -> 4096 bytes
     TestGit.md |   3 +++
     2 files changed, 3 insertions(+)
     create mode 100644 .test.swp
    

    说明:pull 命令直接拉取数据到远程分支并且合并数据到master分支。

    11. 分支

    • 创建并切换分支
    $git checkout -b dev
    Switched to a new branch 'dev'
    

    说明:-b 参数 意思是 创建并切换分支,相当于下面两条命令

    $ git branch dev 创建分支
    $ git checkout dev 切换分支
    Switched to branch 'dev'
    
    • 查看当前分支
    $git branch
    * master
    
    $git checkout -b dev
    Switched to a new branch 'dev'
    
    $git status
    On branch dev
    nothing to commit, working directory clean
    
    $git branch
    * dev
      master
    

    说明:核心命令--git branch,并用 * 指向当前所在分支

    • 合并分支
    $git branch
    * dev
      master
    
    $vim TestGit.md
    
    $git checkout master
    M   TestGit.md
    Switched to branch 'master'
    Your branch is up-to-date with 'origin/master'.
    
    $git branch
      dev
    * master
    
    $git merge dev
    Already up-to-date.
    

    说明:操作步骤如下
    ① 在dev分支上编辑TestGit
    ② 切换到master分支
    ③ 合并dev到当前分支master

    • 删除分支
    $git branch -d dev
    Deleted branch dev (was 555af4a).
    

    12. 解决冲突

    • 场景分析和解决办法
      一个文件,两个分支,每个分支都对文件中的相同一句话做了不同的修改。当一个分支修改完提交后,另外一个分支修改提交,然后合并另外一个分支的时候就会产生冲突,而解决的方法就是继续修改文件,把两个分支都操作的那句话进行最终编辑,然后提交即可。
    创建并切换到dev分支
    $git checkout -b dev
    M   TestGit.md
    Switched to a new branch 'dev'
    
    编辑TestGit.md文件
    $vim TestGit.md
    
    编辑以后:
    Hello World
    Hello Chuizi
    Hello XIAOMI
    
    暂存
    $git add TestGit.md
    
     提交
    $git commit TestGit.md -m "dev commit file"
    [dev 6a31928] dev commit file
     1 file changed, 1 insertion(+)
    
    切换到master分支
    $git checkout master
    Switched to branch 'master'
    Your branch is up-to-date with 'origin/master'.
    
    编辑TestGit.md文件
    $vim TestGit.md
    
    编辑以后:
    Hello World
    Hello Chuizi
    Hello HUAWEI
    
    暂存
    $git add TestGit.md 
    
    提交
    $git commit TestGit.md -m "master commit file"
    [master b62ed88] master commit file
     1 file changed, 1 insertion(+)
    
    合并
    $git merge dev
    Auto-merging TestGit.md
    CONFLICT (content): Merge conflict in TestGit.md
    Automatic merge failed; fix conflicts and then commit the result.
    
    编辑TestGit.md文件
    $vim TestGit.md
    
    Hello World
    Hello Chuizi
    <<<<<<< HEAD
    Hello HUAWEI
    =======
    Hello XIAOMI
    >>>>>>> dev
    

    说明:=======上面是HEAD(master)版本 >>>>>>>上面是dev版本

    解决冲突--进行编辑:
    Hello World
    Hello Chuizi
    Hello HUAWEI
    Hello XIAOMI
    
    暂存
    $git add TestGit.md 
    
    提交
    $git commit TestGit.md 
    fatal: cannot do a partial commit during a merge.
    

    说明:出现冲突以后,修改文件解决冲突后,不能提交部分文件

    上面的commit修改为提交所有文件即可
    $git commit -m "merge files"
    [master 39791ca] merge files
    
    • 查看分支的合并图:
    $git log --graph --pretty=oneline --abbrev-commit
    *   39791ca merge files
    |\  
    | * 6a31928 dev commit file
    * | b62ed88 master commit file
    |/  
    * 555af4a first commit
    

    从合并图可以看出来是dev和master的合并:
    ① 555af4a first commit :首次的提交
    ② 6a31928 dev commit file b62ed88 master commit file :dev先提交master后提交
    ③ 39791ca merge files :解决冲突后合并提交

    13. 变基

    $git log --graph --pretty=oneline --abbrev-commit
    *   39791ca merge files
    |\  
    | * 6a31928 dev commit file
    * | b62ed88 master commit file
    |/  
    * 555af4a first commit
    
    • 上面是分支冲突后的合并图log,你会发现非常混乱,两个commit一个merge,并不在一条直线上。而这仅仅是一次冲突的合并。合并越多,历史log越乱!一个项目的合并次数可能达到成百上千,如果历史合并log非常混乱,会对阅读造成非常大的障碍,影响工作效率,那能否左边的图是一条直线而非菱形呢?答案是肯定的,当本地出现冲突的时候使用变基--rebase来替代合并--merge。
    • 那为什么merge后会产生菱形历史?这就要从其实质说起 : dev 分支、master 分支、两者的共同祖先一起合并生成新的快照,我们称这种提交叫做“合并提交",而合并提交并非只有一个父提交,这里有两个dev和master。所以合并历史图出现了菱形。
    复现冲突场景:dev和master分别修改了同一个文件的相同地方,并且执行了暂存和提交,然后我们这里执行rebase操作:
    $git checkout dev
    Switched to branch 'dev'
    
    $git rebase master
    First, rewinding head to replay your work on top of it...
    Applying: dev commit
    Using index info to reconstruct a base tree...
    M   TestGit.md
    Falling back to patching base and 3-way merge...
    Auto-merging TestGit.md
    CONFLICT (content): Merge conflict in TestGit.md
    error: Failed to merge in the changes.
    Patch failed at 0001 dev commit
    The copy of the patch that failed is found in: .git/rebase-apply/patch
    
    When you have resolved this problem, run "git rebase --continue".
    If you prefer to skip this patch, run "git rebase --skip" instead.
    To check out the original branch and stop rebasing, run "git rebase --abort".
    

    说明:rebase失败,让先解决冲突,然后用 "git rebase --continue"

    $vim TestGit.md
    
    $git add TestGit.md 
    
    $git rebase --continue
    Applying: dev commit
    
    $git checkout master
    Switched to branch 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
      (use "git push" to publish your local commits)
    
    $git merge dev
    Updating 6321248..ce50a7f
    Fast-forward
     TestGit.md | 1 +
     1 file changed, 1 insertion(+)
    
    $git log --graph --pretty=oneline --abbrev-commit
    * ce50a7f dev commit
    * 6321248 master commit
    * 555af4a first commit
    
    • 为什么变基可以实现一条线的历史提交效果呢?那我们也看看其原理:首先找到两个要整合的分支(你当前所在的分支和要整合到的分支)的共同祖先,然后取得当前所在分支的每次提交引入的更改(diff),并把这些更改保存为临时文件,这之后将当前分支重置为要整合到的分支,最后在该分支上依次引入之前保存的每个更改。说白了就是记录dev的更改并保存,然后把保存的更改依次引入master分支,这样相当于所有的更改都在master上。merge和rebase的结果相同,但是提交历史完全不同。
    • 你说还不明白,还是没有看出区别!但是你仔细想想其实区别很大:变基实际上是抛弃了dev的已有的提交,随后创建了新的对应提交,内容相似,但是却是不同的提交。

    14. 后续

    如果大家喜欢这篇文章,欢迎点赞;如果想看更多 Git 方面的技术,欢迎关注!

    相关文章

      网友评论

      • Stone_Birds:关注,持续
        Stone_Birds:@剑走偏锋雨 😀😀😀😀
        付凯强:@Stone_Birds 努力更好,谢谢关注
      • 208459c3c44c:nice,很实用。
        付凯强:更新了变基,增加了从远程数据库拉取数据的操作。
        付凯强:@空白格_b3ac 还缺少一个 很重要的部分,更新后我和你说。

      本文标题:看完不会Git命令行我跪搓板

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