zoukankan      html  css  js  c++  java
  • 多人场景Git演练

    本文基于中国科学技术大学软件学院孟宁老师博客《五⼤场景玩转 Git,只要这一篇就够了!》

    1.前言

    入学后选择了孟宁老师的高级软件工程课,感觉孟宁老师讲的非常细致,并且提供了很多有用的课外资料,因此感谢孟宁老师细心指导。
    那么接下来进入正题,讲讲我对git的理解~~

    2.git是什么?

    git 是一种分布式版本控制系统,能记录代码版本改动,具备团队协作功能,非常方便

    3.几个概念

    3.1. 工作区(Working Directory):在电脑里能看到的目录,你编辑代码的地方
    3.2. 暂存区(Stage or Index):当前哪些改动是被git所追踪的(对的,不是所有修改都会被追踪,所以你需要把修改添加到暂存区,否则可能就会丢失)
    3.3. 版本库(Repository):存储代码版本的仓库,在.git目录中(跟暂存区不同的是,把修改提交到这里会形成一个版本号,这样就能在git的分支树上体现出来了~~)

    3.4. 远程库(Remote Repository):在服务器上存储代码的仓库。作为本地仓库的备份,也可以通过远程仓库进行多人协作,如果你不想因为意外丢掉你的代码,请一定记得把本地仓库的最新修改同步到远程仓库

    4.多人场景演练

    4.1 建立远程库

    这个没啥好说的,在自己的github域名下建一个仓库就行

    4.2 建立本地库


    由于远程库中没有任何内容,需要新建本地库然后与远程库关联起来。如图,先新建本地仓库,再使用git init命令初始化本地仓库,如此一来,就可以在这个仓库里放代码了
    接下来来点java代码试试?

    public class GitTest {
        public static void main(String[] args) {
            System.out.println("Hello World!");
        }
    }
    

    新增代码文件后,使用git add fileName命令,可以把代码文件从工作区添加进暂存区,接下来继续修改下代码文件,使用git status可以查看当前工作区,暂存区,和未追踪文件的状态

    接下来使用git commit -m "第一次提交"把暂存区的文件提交到本地仓库中,这样就在本地形成一个版本号

    4.3 关联远程库

    git remote add origin https://github.com/JohnsonGreen/GitTest.git
    git push -u origin master
    

    在本地仓库增加远程库,并推送到远程库的master分支

    4.4 建立个人开发分支

    git checkout -b mybranch
    

    不加-b参数则是直接切换到该分支。接下来我们新增一些代码,并推送到远程

    public class GitTest {
        public static void main(String[] args) {
            System.out.println("Hello World!");
            System.out.println("Hello ChenHeng");
        }
    }
    

    此时使用git log --oneline --graph显示本地和远程都已经有两个节点

    4.5 与同事协同开发

    同事可以把远程仓库的内容完整的下载到本地,形成本地仓库,并建立他的分支。由于同事是个急性子,我才刚刚在远程master上推送了第一个结点"Hello World!",他就把代码clone下来了,并在此基础上建立了新的分支(不幸的是,我随后又在远程的master分支上增加了新的结点,猜猜他之后合并到master上会发生什么?)

    git clone https://github.com/JohnsonGreen/GitTest.git
    git branch -b hisbranch
    

    加点代码试试

    public class GitTest {
        public static void main(String[] args) {
            System.out.println("Hello World!");
            System.out.println("Hello ChenYuHong"); 
        }
    }
    

    然后推送到远程建立远程的hisbranch分支,并且此时想合并到远程的master分支,那么做法是,先在本地切换到master分支,然后使用git pull 将最新的内容更新到master分支,再使用 git merge --no-ff hisbranch (使用--no-ff参数可以在git分支树上看到分叉 )合并到本地的master分支,但是,能合并成功吗?

    4.6 冲突解决

    public class GitTest {
        public static void main(String[] args) {
            System.out.println("Hello World!");
    <<<<<<< HEAD
            System.out.println("Hello ChenHeng");
    =======
            System.out.println("Hello ChenYuHong");
    >>>>>>> hisbranch
        }
    }
    

    我们看到,命令提示有冲突,并且代码中标注出了冲突位置,那这就需要选择保留哪一项了。保留之后,就可以add,commit以及push了。注意:在改同事代码的时候记得一定联系下他,否则可能被打~~
    合并之后的分支树如图所示

    4.7 吃后悔药

    上次merge之后,有点后悔合并了,想还是继续回到第一次提交时"hello world"的状态,那么在通过git log --graph查找到该commit ID后,就可以使用下面这个命令完成回退啦!

    git reset --hard 54a05c8
    

    然后瞬间在master分支上只有一个结点了,惊不惊喜,意不意外?

    4.8 吃后悔药的后悔药

    经过上次回退之后,感觉又想把merge之后的代码找回来,但是此时只剩一个孤零零的"Hello World!",之前写的代码全丢了,这可咋办?
    答案是依旧使用git reset --hard 命令,但是commit ID要怎么找?
    然后时光机神器出现了

    git reflog 
    

    还好还好,有了git reflog这个能记录你所有git操作的大神器,妈妈再也不用担心我的代码丢失了

    于是我们找到merge结点的commit ID,然后就可以乘坐时光机回到未来了


    4.8 终结杂乱无章的提交

    现在,我的同事要向孟宁老师打招呼,但是同事是个结巴,只能一个字母一个字母的打,于是我们在同事的提交记录上看到了一长串的commit,并且每个commit也就只打了一个字母

    但是这一个一个字母形成的commit终究只是为了完成"Hello Meng Ning"这个打招呼的功能,真的有必要写这么多commit吗?
    接下来我们使用git rebase -i [startCommitID] [endCommitId]这个命令,来让同事的招呼打得更顺畅一些。

    git rebase -i dc8e07b
    

    在上图中我们删除除了最后一条的所有commit,只保留最后一条commit
    然后出现了冲突,如下

    public class GitTest {
        public static void main(String[] args) {
            System.out.println("Hello World!");
            System.out.println("Hello ChenYuHong");
    <<<<<<< HEAD
    =======
            System.out.println("Hello Meng Ning");
    >>>>>>> 1704756... 添加g
        }
    }
    

    我们当然要保留向孟宁老师打招呼的内容,修改之后把内容add进暂存区,并使用git rebase --continue完成rebase操作,此时会跳出编辑框,让我们把保留的这个commit的说明改一下,从"添加g"改为"向孟宁老师打招呼", 保存并提交,然后合并到master,并推送到远程库

    从而我们在继续查看远程库的master分支时,就不会继续包含那些"结巴"的commit啦!

    5. 一点小小的补充

    5.1 为什么需要暂存区?

    做某件事情的时候可能会改好几个文件,例如a、b、c三个文件,其中a和b文件是代码逻辑的修改,c文件是文案修改。这个时候为了让提交日志更可读,会先提交a和b,再提交c,于是就有如下的git操作

           git add a b
           git commit -m' change logic'
           git add c
           git commit -m 'change text'
    

    如果没有暂存区这个东西,那只可能有一条提交,这个提交包含了逻辑调整和文案修改(可能是两件毫不相干的事情)

    5.2 git push --force /-f 命令有什么安全问题?

    --force 会使用本地分支的提交覆盖远端推送分支的提交。也就是说,如果其他人在相同的分支推送了新的提交,你的这一举动将“删除”他的那些提交!就算在强制推送之前先 fetch 并且 merge 或 rebase 了也是不安全的,因为这些操作到推送之间依然存在时间差,别人的提交可能发生在这个时间差之内.
    2018年9月19日,一名程序员在美国某办公楼向4名同事开枪,导致一人情况危机,两人伤情严重,一人被子弹擦伤。目前,凶手已死,身份被警方查明。 目前,码农持枪杀人的动机仍然是个谜。有人猜测道:“同事不写注释,不遵循驼峰命名,括号换行,最主要还天天 git push -f 等因素” 激怒了这名行凶者。

    5.3 git reset 和 git revert 有什么区别?

    二者最大的区别是git revert是用新的一个commit来回滚之前的commit,HEAD是要继续前进,但是git reset是直接删除指定的HEAD,其是相当于在不断后退

    5.4 版本回退之后,想吃后悔药怎么办?

        1) revert: 两次revert ,负负得正
        2) 如果知道回退之前的HEAD所指向的结点的版本号,那么依然可以使用 git reset --hard e475afc 来实现

    5.5 正在dev分支进行开发,但是突然在master分支上有紧急bug要修复,怎么办?

        1)git stash save "增加readme.md2"
    会将工作区和暂存区的内容储藏起来,前提是这些文件已经被git追踪
    储藏未跟踪的文件:git stash save -ugit stash save --include-untracked
        2)git stash list
    查看储藏列表

              stash@{0}: On dev: 修改为Yes
              stash@{1}: On dev: 增加readme.md2
    

        3)git stash apply1
    应用最顶层的stash, 也可以指定哪个stash: git stash apply stash@{1}
    git stash pop 与之类似,但会删除stashs
    stash 之后又对同一个位置做了修改,造成冲突?
    先对修改进行commit或者git stash
        4)git stash drop stash@{1}
    删除某个stash或者git stash clear 清除所有stash
        5)git stash show -p stash@{1}
    查看当前分支与某个stash的对比
        6)git stash branch newBranch stash@{1}
    有的时候可以将储藏起来的代码应用到新建的分支,而不是当前分支上

    5.6 如果只是想丢弃掉工作区的内容,该怎么做?

        1) git reset --hard HEAD
    直接重置版本号(丢弃掉所有文件在工作区的修改 + 已经add到暂存区但没有commit的修改,需要谨慎使用
    变种: git reset HEAD~1 或 git reset HEAD^ (均是回退到HEAD之前的一个版本)
        2)git checkout -- filename (针对选中的文件,可以添加多个)
    这个操作总是让这个文件回到最近一次 git commit 或 git add 时的状态(commit之后修改没有add或add之后又做了修改),都是丢弃工作区的修改(修改包含删除操作)。
    git checkout . 放弃当前目录下的修改
        3) 推荐使用git stash, 万一后悔了呢?

    5.7 merge错了分支,咋办?

    git merge --abort
    该命令仅仅在合并后导致冲突时才使用。git merge --abort将会抛弃合并过程并且尝试重建合并前的状态。但是,当合并开始时如果存在未commit的文件,git merge --abort在某些情况下将无法重现合并前的状态

    5.8 在发布版本号的时候,怎么给结点打标签?

        1)git tag -a v1.4 -m "my version 1.4"
    会在当前分支上的HEAD结点打上打标签
        2) git tag -a v1.1 -m "my tag" a0472e6
    给某一个结点打标签
        3) 推送标签到远程仓库
    push单个tag,命令格式为git push origin [tagname]

  • 相关阅读:
    Python+selenium常见报错
    jmeter压力测试指标解释
    jemte自动生成测试报告方法
    iview清空Date-picker组件后请求报错解决方法
    【求助】Django+vue项目时候遇到一个问题,table的data数据怎么更新
    django_数据库操作—增、删、改、查
    django-关于manage.py migrate无效的问题
    python家里的环境和公司环境怎么同步
    python class类的属性应用及init初始化实践 ---勇者斗恶龙
    IDLE与pycharm执行相同代码结果却不同,原因分析
  • 原文地址:https://www.cnblogs.com/--CYH--/p/13779385.html
Copyright © 2011-2022 走看看