zoukankan      html  css  js  c++  java
  • Git & github 入门(上)

    本节内容

    1. github介绍
    2. 安装
    3. 仓库创建& 提交代码
    4. 代码回滚
    5. 工作区和暂存区
    6. 撤销修改
    7. 删除操作
    8. 远程仓库
    9. 分支管理
    10. 多人协作
    11. github使用
    12. 忽略特殊文件.gitignore

    前戏

    为什么要用版本控制?

    假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,上线没2天,就发现这个功能用户并不喜欢,你老板让你去掉这个功能,你怎么办?你说简单,直接把5000行代码去掉就行了,但是我的亲,说的简单,你的这个功能写了3周时间,但你还能记得你是新增加了哪5000行代码么?所以你急需要一个工具,能帮你记录每次对代码做了哪些修改,并且可以轻易的把代码回滚到历史上的某个状态。 这个神奇的工具就叫做版本控制。 

     

    版本控制工具主要实现2个功能:

    1.版本管理

    在开发中,这是刚需,必须允许可以很容易对产品的版本进行任意回滚,版本控制工具实现这个功能的原理简单来讲,就是你每修改一次代码,它就帮你做一次快照

    2.协作开发

    一个复杂点的软件,往往不是一个开发人员可以搞定的,公司为加快产品开发速度,会招聘一堆跟你一样的开发人员开发这个产品,拿微信来举例,现在假设3个人一起开发微信,A开发联系人功能,B开发发文字、图片、语音通讯功能,C开发视频通话功能, B和C的功能都是要基于通讯录的,你说简单,直接把A开发的代码copy过来,在它的基础上开发就好了,可以,但是你在他的代码基础上开发了2周后,这期间A没闲着,对通讯录代码作了更新,此时怎么办?你和他的代码不一致了,此时我们知道,你肯定要再把A的新代码拿过来替换掉你手上的旧通讯录功能代码, 现在人少,3个人之间沟通很简单,但想想,如果团队变成30个人呢?来回这样copy代码,很快就乱了, 所以此时亟需一个工具,能确保一直存储最新的代码库,所有人的代码应该和最新的代码库保持一致

    常见版本管理工具介绍

    1、VSS-- Visual Source Safe
    此工具是Microsoft提供的,是使用的相当普遍的工具之一,他可以与VS.net进行无缝集成,成为了独立开发人员和小型开发团队所适合的工具,基本上Window平台上开发的中小型企业,当规模较大后,其性能通常是无法忍受的,对分支与并行开发支持的比较有限。

    2、CVS--Concurrent Versions System,
    此工具是一个开源工具,与后面提到的SVN是同一个厂家:Collab.Net提供的。
    CVS是源于unix的版本控制工具,对于CVS的安装和使用最好对unix的系统有所了解能更容易学习,CVS的服务器管理需要进行各种命令行操作。目前,CVS的客户端有winCVS的图形化界面,服务器端也有CVSNT的版本,易用性正在提高。
    此工具是相当著名,使用得相当广泛的版本控制工具之一,使用成熟的“Copy-Modify-Merge"开发模型,可以大大的提高开发效率,适合于项目比较大,产品发布频繁,分支活动频繁的中大型项目。

    3、SVN --CollabNet Subversion
    此工具是在CVS 的基础上,由CollabNet提供开发的,也是开源工具,目前越来越受到大家的欢迎,估计将来可能会成为最著名,使用最广泛的工具。
    他修正cvs的一些局限性,适用范围同cvs,目前有一些基于SVN的第三方工具,如TortoiseSVN,是其客户端程序,使用的也相当广泛。在权限管理,分支合并等方面做的很出色,他可以与Apache集成在一起进行用户认证。
    不过在权限管理方面目前还没有个很好用的界面化工具,SVNManger对于已经使用SVN进行配置的项目来说,基本上是无法应用的,但对于从头开始的项目是可以的,功能比较强大,但是搭建svnManger比较麻烦。
    是一个跨平台的软件,支持大多数常见的操作系统。作为一个开源的版本控制系统,Subversion 管理着随时间改变的数据。 这些数据放置在一个中央资料档案库中。 这个档案库很像一个普通的文件服务器, 不过它会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。Subversion 是一个通用的系统, 可用来管理任何类型的文件, 其中包括了程序源码。


    4. GIT
    因为最初是从Linux起家的,非常依赖文件系统的一些特性,这些在 Linux 下表现的很好,而 Windows 下特别糟糕Git 中文教程
    Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理.
    Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
    Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper,后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人觉得 BitKeeper 的许可证并不适合开放源码社区的工作,因此 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是我们已经发现在很多其他自由软件项目中也使用了 Git。例如 最近就迁移到 Git 上来了,很多 Freedesktop 的项目也迁移到了 Git 上。

    5、BitKeeper
    是由BitMover公司提供的,BitKeeper自称是“分布式”可扩缩SCM系统。
    不是采用C/S结构,而是采用P2P结构来实现的,同样支持变更任务,所有变更集的操作都是原子的,与svn,cvs一致。

    1.Github介绍

    1.github介绍
    
    很多人都知道,Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。
    
    Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?
    
    事实是,在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码!
    
    你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。
    
    不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
    
    安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错!),于是BitMover公司怒了,要收回Linux社区的免费使用权。
    
    Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:
    
    Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。
    
    Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了(github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开。),它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
    
    历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
    
     
    
    今天,GitHub已是:
    
    一个拥有143万开发者的社区。其中不乏Linux发明者Torvalds这样的顶级黑客,以及Rails创始人DHH这样的年轻极客。
    这个星球上最流行的开源托管服务。目前已托管431万git项目,不仅越来越多知名开源项目迁入GitHub,比如Ruby on Rails、jQuery、Ruby、Erlang/OTP;近三年流行的开源库往往在GitHub首发,例如:BootStrap、Node.js、CoffeScript等。
    alexa全球排名414的网站。
    View Code

    2. git安装

    安装Git

    最早Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上跑。不过,慢慢地有人把它移植到了Windows上。现在,Git可以在Linux、Unix、Mac和Windows这几大平台上正常运行了。

     要使用Git,第一步当然是安装Git了。根据你当前使用的平台来阅读下面的文字:

    在Linux上安装Git

    首先,你可以试着输入git,看看系统有没有安装Git:

    $ git
    The program 'git' is currently not installed. You can install it by typing:
    sudo apt-get install git

    像上面的命令,有很多Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git。

    如果你碰巧用Debian或Ubuntu Linux,通过一条sudo apt-get install git就可以直接完成Git的安装,非常简单。

    3.版本库创建

    什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

    所以,创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录:

    $ mkdir git_trainning
    $ cd git_trainning/
     
    $ git init
    Initialized empty Git repository in /Users/alex/git_trainning/.git/
    

    瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

    如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。

    把文件添加到版本库

    首先这里再明确一下,所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。

    不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,前面我们举的例子只是为了演示,如果要真正使用版本控制系统,就要以纯文本方式编写文件。

    因为文本是有编码的,比如中文有常用的GBK编码,日文有Shift_JIS编码,如果没有历史遗留问题,强烈建议使用标准的UTF-8编码,所有语言使用同一种编码,既没有冲突,又被所有平台所支持。

    言归正传,现在我们编写一个first_git_file.txt文件,内容如下:

    $ vim first_git_file.txt
     
    first time using git, excited!
    第一次用git哈哈
    

    一定要放到git_trainning目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。

    和把大象放到冰箱需要3步相比,把一个文件放到Git仓库只需要两步。

    第一步,用命令git add告诉Git,把文件添加到仓库:

    1
    $ git add first_git_file.txt

    执行上面的命令,没有任何显示,说明添加成功。

    第二步,用命令git commit告诉Git,把文件提交到仓库:  

    $ git commit -m "commit my first git file"
     
    [master (root-commit) 621e6e4] commit my first git file
     Committer: Alex Li <alex@alexs-macbook-pro.local>
    Your name and email address were configured automatically based
    on your username and hostname. Please check that they are accurate.
    You can suppress this message by setting them explicitly. Run the
    following command and follow the instructions in your editor to edit
    your configuration file:
     
        git config --global --edit
     
    After doing this, you may fix the identity used for this commit with:
     
        git commit --amend --reset-author
     
     1 file changed, 2 insertions(+)
     create mode 100644 first_git_file.txt
    </alex@alexs-macbook-pro.local>
    

    中间红色部分的意思是,你在往git库里提交代码时,你需要告诉git你是谁,这样git就会纪录下来是谁改的代码,其实就是为了日后查询方便,你只需要提供一个名字和邮件地址就可以,这里我的git直接通过主机名自己创建了一个,但你可以通过git config --global --edit修改

    简单解释一下git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。

    嫌麻烦不想输入-m "xxx"行不行?确实有办法可以这么干,但是强烈不建议你这么干,因为输入说明对自己对别人阅读都很重要。

    为什么Git添加文件需要addcommit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

    $ git add file1.txt
    $ git add file2.txt file3.txt
    $ git commit -m "add 3 files."
    

    4. 代码回滚

    4.1代码修改并提交  

    我们已经成功地添加并提交了一个first_git_file.txt文件,现在,是时候继续工作了,于是,我们继续修改first_git_file.txt文件,改成如下内容:

    First time using git, excited! update ...
    insert line here...
    第一次用git哈哈
    

    现在,运行git status命令看看结果:

    $ 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:   first_git_file.txt
     
    no changes added to commit (use "git add" and/or "git commit -a")
    

    虽然Git告诉我们first_git_file.txt被修改了,但如果能看看具体修改了什么内容,自然是很好的。比如你休假两周从国外回来,第一天上班时,已经记不清上次怎么修改的readme.txt,所以,需要用git diff这个命令看看:

    $ git diff first_git_file.txt
    diff --git a/first_git_file.txt b/first_git_file.txt
    index 2d13c2c..248d853 100644
    --- a/first_git_file.txt
    +++ b/first_git_file.txt
    @@ -1,3 +1,4 @@
    -first time using git, excited!
    +First time using git, excited! update ...
     insert line here...
     第一次用git哈哈
    +insert line again haha...
    

    输出中+号绿色显示的就是修改或新增的内容,-号红色显示的就是去掉或被修改的内容

    知道了对first_git_file.txt 作了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件是一样的两步,第一步是git add

    $ git add . # .  代表把当前目录下所有改动的文件都提交到代码库
    Alexs-MacBook-Pro:git_trainning alex$ git commit -m "commit changes"
    [master 50ad6b5] commit changes
     Committer: Alex Li <alex@Alexs-MacBook-Pro.local>
     1 file changed, 1 insertion(+)
    

    提交后,我们再用git status命令看看仓库的当前状态:

    $ git status
    # On branch master
    nothing to commit (working directory clean)
    

    Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working directory clean)的。 

    4.2 代码回滚

    现在,你已经学会了修改文件,然后把修改提交到Git版本库,现在,再练习一次,修改first_git_file.txtt文件如下: 

    First time using git, excited! update ...
    insert line here..改之前的.
    第一次用git哈哈
    insert line again haha...
    加点新内容 
    
    然后尝试提交:
    
    
    $ git add first_git_file.txt
    $ git commit -m "add new content"
    [master 4459657] add new content
     Committer: Alex Li <alex@Alexs-MacBook-Pro.local>
     1 file changed, 2 insertions(+), 1 deletion(-)
    

    像这样,你不断对文件进行修改,然后不断提交修改到版本库里,就好比玩RPG游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss之前,你会手动存盘,以便万一打Boss失败了,可以从最近的地方重新开始。Git也是一样,每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。

    现在,我们回顾一下first_git_file.txt文件一共有几个版本被提交到Git仓库里了: 

    版本1
    first time using git, excited!
    第一次用git哈哈
    
    
    版本2
    first time using git, excited!
    insert line here...
    第一次用git哈哈
    
    
    版本3
    first time using git, excited!
    insert line here...
    第一次用git哈哈
    insert line again haha...
    
    
    版本4
    First time using git, excited! update ...
    insert line here..改之前的.
    第一次用git哈哈
    insert line again haha...
    加点新内容
    

    当然了,在实际工作中,我们脑子里怎么可能记得一个几千行的文件每次都改了什么内容,不然要版本控制系统干什么。版本控制系统肯定有某个命令可以告诉我们历史记录,在Git中,我们用git log命令查看:

    $ git log
    commit 445965781d1fd0d91e76d120450dd18fd06c7489
    Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    Date:   Tue Oct 4 18:44:29 2016 +0800
     
        add new content
     
    commit be02137bb2f54bbef0c2e99202281b3966251952
    Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    Date:   Tue Oct 4 17:55:16 2016 +0800
     
        update again
     
    commit 50ad6b526810bb7ccfea430663757ba2337b9816
    Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    Date:   Tue Oct 4 17:46:51 2016 +0800
     
        commit changes
     
    commit 621e6e44d04fa6a1cdc37826f01efa61b451abd1
    Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    Date:   Tue Oct 4 17:42:50 2016 +0800
     
        commit my first git file
    

    git log命令显示从最近到最远的提交日志,我们可以看到4次提交,最近的一次是add new content,上一次是update again,最早的一次是commit my first git file。 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

    $ git log --pretty=oneline
    445965781d1fd0d91e76d120450dd18fd06c7489 add new content
    be02137bb2f54bbef0c2e99202281b3966251952 update again
    50ad6b526810bb7ccfea430663757ba2337b9816 commit changes
    621e6e44d04fa6a1cdc37826f01efa61b451abd1 commit my first git file

    需要友情提示的是,你看到的一大串类似3628164...882e1e0的是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。

    回滚回滚回滚  

    好了,现在我们启动时光穿梭机,准备把first_git_file.txt回退到上一个版本,也就是“update again”的那个版本,怎么做呢?

    首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交be02137bb2f54bbef0c2e99202281b3966251952(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

    现在,我们要把当前版本“add new content”回退到上一个版本“update again”,就可以使用git reset命令:

    $ git reset --hard HEAD^

    HEAD is now at be02137 update again
     
    此时再看你的文件内容,果然就退回去了
    more first_git_file.txt
    First time using git, excited! update ...
    insert line here...
    第一次用git哈哈
    insert line again haha...
     
    此时还可以继续再往前回退一个版本,不过且慢,然我们用git log再看看现在版本库的状态:

    $ git log --pretty=oneline

    be02137bb2f54bbef0c2e99202281b3966251952 update again
    50ad6b526810bb7ccfea430663757ba2337b9816 commit changes
    621e6e44d04fa6a1cdc37826f01efa61b451abd1 commit my first git file
     

    最新的那个版本add new content已经看不到了!好比你从21世纪坐时光穿梭机来到了19世纪,想再回去已经回不去了,肿么办?

    办法其实还是有的,只要上面的命令行窗口还没有被关掉,你就可以顺着往上找啊找啊,找到那个add new content的commit id是445965781d1fd0d91e76d120450dd18fd06c7489

    ,于是就可以指定回到未来的某个版本:

    git reset --hard 4459657

    HEAD is now at 4459657 add new content

    版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。

    再小心翼翼地看看first_git_file.txt的内容:

    First time using git, excited! update ...

    insert line here..改之前的.
    第一次用git哈哈
    insert line again haha...
    加点新内容
     

    果然,我胡汉三又回来了。

    Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD从指向add new content

    现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?

    在Git中,总是有后悔药可以吃的。当你用$ git reset --hard HEAD^回退到update again版本时,再想恢复到最新add new content的版本,就必须找到add new contentL的commit id。Git提供了一个命令git reflog用来记录你的每一次命令:

    $ git reflog

    4459657 HEAD@{0}: reset: moving to 4459657
    be02137 HEAD@{1}: reset: moving to HEAD^
    4459657 HEAD@{2}: commit: add new content
    be02137 HEAD@{3}: reset: moving to be02137bb
    50ad6b5 HEAD@{4}: reset: moving to 50ad6b5
    621e6e4 HEAD@{5}: reset: moving to 621e6e44
    50ad6b5 HEAD@{6}: reset: moving to HEAD^
    be02137 HEAD@{7}: commit: update again
    50ad6b5 HEAD@{8}: commit: commit changes
    621e6e4 HEAD@{9}: commit (initial): commit my first git file

    终于舒了口气,第二行显示add new content的commit id是4459657,现在,你又可以乘坐时光机回到未来了。

    5. 工作区和暂存区

    Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。

    先来看名词解释。

    工作区(Working Directory

    就是你在电脑里能看到的目录,比如我的git_trainning文件夹就是一个工作区:

    $ ls git_trainning/
    first_git_file.txt
    

    版本库(Repository)

    工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

    Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

    分支和HEAD的概念我们以后再讲。

    前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

    第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

    第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

    因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

    你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

    俗话说,实践出真知。现在,我们再练习一遍,先对first_git_file.txt做个修改,比如加上一行内容:

      First time using git, excited! update ...

      insert line here..改之前的.
      第一次用git哈哈
      insert line again haha...
      加点新内容
      update v5

    然后,在工作区新增一个readme.md文本文件(内容随便写)。

    先用git status查看一下状态:

    $ 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:   first_git_file.txt
     
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
     
        readme.md
     
    no changes added to commit (use "git add" and/or "git commit -a")
    

    Git非常清楚地告诉我们,first_git_file.txt被修改了,而readme.md还从来没有被添加过,所以它的状态是Untracked

    现在,使用命令git add . ,再用git status再查看一下:

    $ git add .
    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
     
        modified:   first_git_file.txt
        new file:   readme.md
    </file>
    

    现在,暂存区的状态就变成这样了:

    (盗图关系, 这里readme.txt = first_git_file.txt , LICENSE = readme.md)

    所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

    $ git commit -m "知道暂存区stage的意思了"

    [master 9d65cb2] 知道暂存区stage的意思了
     2 files changed, 2 insertions(+)
     create mode 100644 readme.md

    一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:

    $ git status

    On branch master
    nothing to commit, working directory clean

    现在版本库变成了这样,暂存区就没有任何内容了:

    (盗图关系, 这里readme.txt = first_git_file.txt , LICENSE = readme.md)

     暂存区是Git非常重要的概念,弄明白了暂存区,就弄明白了Git的很多操作到底干了什么。

    6. 撤销修改  

    自然,你是不会犯错的。不过现在是凌晨两点,你正在赶一份工作报告,你在readme.md中添加了一行:

    #git study repo

    git is great
    but my stupid boss still prefers SVN.

    在你准备提交前,一杯咖啡起了作用,你猛然发现了“stupid boss”可能会让你丢掉这个月的奖金!

    既然错误发现得很及时,就可以很容易地纠正它。你可以删掉最后一行,手动把文件恢复到上一个版本的状态。如果用git status查看一下:

    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:   readme.md
     
    no changes added to commit (use "git add" and/or "git commit -a")
    </file></file>
    你可以发现,Git会告诉你,git checkout -- file可以丢弃工作区的修改:
    $ git checkout -- readme.md
     
    more readme.md
    #git study repo

    你刚才添加的2行骂老板的话就被撤销了,

    命令git checkout -- readme.md意思就是,把readme.md文件在工作区的修改全部撤销,这里有两种情况:

    一种是readme.md自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

    一种是readme.md已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

    总之,就是让这个文件回到最近一次git commitgit add时的状态。

    git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。  

    现在假定是凌晨3点,你不但写了一些胡话,还git add到暂存区了:

    $ cat readme.md
    Git is a distributed version control system.
    Git is free software distributed under the GPL.
    Git has a mutable index called stage.
    Git tracks changes of files.
    My stupid boss still prefers SVN.
     
    $ git add readme.md
    

    庆幸的是,在commit之前,你发现了这个问题。用git status查看一下,修改只是添加到了暂存区,还没有提交: 

    $ git status
    On branch master
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
     
        modified:   readme.md
    </file>

    Git同样告诉我们,用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:
    $ git reset HEAD readme.md Unstaged changes after reset: M readme.md
    git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。 再用git status查看一下,现在暂存区是干净的,工作区有修改
    $ 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: readme.md # no changes added to commit (use "git add" and/or "git commit -a")
    还记得如何丢弃工作区的修改吗?
    $ git checkout -- readme.md $ more readme.md #git study repo 整个世界终于清静了!

    7. 删除操作

    在Git中,删除也是一个修改操作,我们实战一下,先添加一个新文件test.txt到Git并且提交:  

    $ git add .
    $ git commit -m "add test.txt"
    [master a8fa95a] add test.txt
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 test.txt
    

    一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了:rm test.txt

    这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:

    $ git status
    On branch master
    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:    test.txt
     
    no changes added to commit (use "git add" and/or "git commit -a")
    

    现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit

    x$ git rm test.txt
    rm 'test.txt'
     
    $ git commit -m "remove test"
    [master 03df00a] remove test
     1 file changed, 0 insertions(+), 0 deletions(-)
     delete mode 100644 test.txt
    

    现在,文件就从版本库中被删除了。

    另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:$ git checkout -- test.txt

    git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

    文章太长为了方便阅读请看:

    git &github 快速入门(下)

  • 相关阅读:
    db2中的常用命令及使用方法
    互联网服务应用协议设计
    Zookeeper整理(一)- 写操作产生事件,写操作与Watcher对应关系
    实现自己的连接池(一)
    SMP、NUMA、MPP体系结构介绍
    随手备忘 ubuntu12.04 lts 安装gcc 4.8
    认真体会 结构体中的零长度数组
    由内存池实现总结内存对齐问题
    认真理解 oom killer 备忘
    仔细体会 epoll中的et lt模式
  • 原文地址:https://www.cnblogs.com/runner1/p/6422869.html
Copyright © 2011-2022 走看看