Git入门教程

这是一篇Git入门教程,开始阅读本教程之前,请先仔细阅读目录,巧用目录来快速指引你阅读,无关紧要的目录内容可以跳过。

Git简介

Git是目前世界上最先进的分布式版本控制系统。

  1. 版本控制

    典型代表Word文件的编辑,你的文件夹中是不是有这样的情况:

     word20160301.doc
     word备份的.doc
     word(小王).doc
     word-03.doc
     word.doc
    

    而某一天,你可能需要以前修改过的版本(因为,经常会遇到这种抽风的上司或者客户)

    而由版本控制给你带来的是:

     版本	用户	说明	日期
     1   张三	删除了软件服务条款5	7/12 10:38
     2	张三	增加了License人数限制	7/12 18:09
     3	李四	财务部门调整了合同金额	7/13 9:51
     4	张三	延长了免费升级周期	7/14 15:17
    

    而且,你想退回到哪里,就可以退回到哪里!

    记住第一个关键词:(无尽的)后悔药

  2. 分布式 VS 集中式

    集中式,典型的代表就是SVN,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。

    分布式,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。

    Git不单是不必联网这么简单,Git更强大的是分支管理。后面讲到~~~~

    关于更多SVN&Git的区别可以参见:
    
    [蒋鑫:为什么 Git 比 SVN 好](http://blog.jobbole.com/20069/)
    
    [SVN 和 Git 在日常使用中的明显差异](https://github.com/xirong/my-git/blob/master/why-git.md)
    
    [GIT和SVN之间的五个基本区别](http://www.vaikan.com/5-fundamental-differences-between-git-svn/)
    

    记住第二个关键词:分布式

Git环境搭建

安装Git

* 在Linux(Debian)上安装Git:

    apt-get install git

* Mac OS X上安装Git:

    一是安装homebrew,然后通过homebrew安装Git,具体方法请参考homebrew的文档:[http://brew.sh/](http://brew.sh/)。

    第二种方法更简单,也是推荐的方法,就是直接从AppStore安装Xcode,Xcode集成了Git,不过默认没有安装,你需要运行Xcode,选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Downloads”,选择“Command Line Tools”,点“Install”就可以完成安装了。

* 在Windows上安装Git

    从这里[https://git-for-windows.github.io/](https://git-for-windows.github.io/)下载,双击安装

    安装完成后,可以在右键菜单/开始菜单中找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!

全局变量设置

就像Java需要设置Path一样,Git需要设置一些全局变量。

“Git”->“Git Bash”

$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

设置用户与Email,相当于自报家门,让版本库有一个记录。注意:git config命令的--global是全局设置的意思。

任何一个命令或者参考:git [命令] --help来查看帮助,或者登陆官方来学习命令http://git-scm.com/doc

参考资料:Git 内部原理 - 环境变量

创建版本库

非常简单。

  1. windows下,需要建立的版本库的地方,右键git bash->

     $ git init
    

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

    PS:如果你没有看到.git目录,那是因为这个目录默认是隐藏的

  2. Linux中:

如果,需要在learngit目录下建立一个Git仓库,可以如下操作

$ mkdir learngit
$ cd learngit
$ git init

你也可以这样:

$ git init learngit

试一试吧!

基本操作

Git工作区和暂存区:

我们看到目录为工作区(/learngit);需要进行提交到版本库的文件放在暂存区(看不到,需要使用git status来查看)。

git status命令:可以让我们时刻掌握仓库当前的状态。

git diff命令:让我们查看文件与版本库中的区别。

获取远程仓库代码(前题是init之后)
  1. 克隆仓库:

     $ git clone [user@]example.com:path/to/repo.git/
     
    
  2. 或者添加远程仓库:

    使用git remote add命令,添加一个远程仓库的链接,命令格式:git remote add [远程仓库别名] [远程仓库地址]

     $ git remote add origin git@github.com:michaelliao/learngit.git
    
  3. 拉取代码。

    如果已经被git管理的项目,则使用git pullgit fetch来管理代码的拉取与更新:

    使用git pull拉取远程代码的HEAD头标记,即最新的代码。

    命令格式:$ git pull <远程主机名> <远程分支名>:<本地分支名>

     $ git pull
    
提交代码

把所有的文件更改提交到暂存区:

$ git add -a

为所有暂存区的代码写入日志并提交到本地仓库:

$ git commit -m "(something)"

把所有本地仓库的提交,更新到远程仓库:

$ git push

Git时光机

  1. git log命令:查看每次修改的日志文件。

git log与git reflog的区别,记得几点:git log是顺着当前分支往前去查找提交记录,而git reflog并不像git log去遍历提交历史,它都不是仓库的一部分,它不包含推送、更新或者克隆,而是作为本地提交记录的清单。简单理解:本地后悔药

  1. git reset命令:回退命令。

    首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

     $ git reset --hard HEAD^
     HEAD is now at ea34578 add distributed
    

    回退add命令提交到缓存区的文件,并不会把文件恢复缓存区,需要区别(3)git checkout命令:

     $ git reset HEAD <file>
    
  2. git checkout -- <file>命令:丢弃缓存区文件的修改,把文件恢复到git add之前的状态。

  3. git diff HEAD -- <file>命令可以查看工作区和版本库里面最新版本的区别

  4. git rm删除文件。

标签管理

发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。

  1. 创建标签(快照)

    在Git中打标签非常简单,首先,切换到需要打标签的分支上:

     $ git branch
     * dev
       master
     $ git checkout master
     Switched to branch 'master'
    

    然后,敲命令git tag <name>就可以打一个新标签:

     $ git tag v1.0
    

    可以用命令git tag查看所有标签:

     $ git tag
     v1.0
    

    默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?

    方法是找到历史提交的commit id,然后打上就可以了:

     $ git log --pretty=oneline --abbrev-commit
     6a5819e merged bug fix 101
     cc17032 fix bug 101
     7825a50 merge with no-ff
     6224937 add merge
     59bc1cb conflict fixed
     400b400 & simple
     75a857c AND simple
     fec145a branch test
     d17efd8 remove test.txt
    

    比方说要对add merge这次提交打标签,它对应的commit id是6224937,敲入命令:

     $ git tag v0.9 6224937
    

    再用命令git tag查看标签:

     $ git tag
     v0.9
     v1.0
    

    注意,标签不是按时间顺序列出,而是按字母排序的。

    可以用git show <tagname>查看标签信息:

     $ git show v0.9
     commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4
     Author: Brian <brian@toimc.com>
     Date:   Thu Aug 22 11:22:08 2013 +0800
     
         add merge
     ...
    

    可以看到,v0.9确实打在add merge这次提交上。

    还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:

     $ git tag -a v0.1 -m "version 0.1 released" 3628164
    

    用命令git show <tagname>可以看到说明文字:

     $ git show v0.1
     tag v0.1
     Tagger: Brian <brian@toimc.com>
     Date:   Mon Aug 26 07:28:11 2013 +0800
     
     version 0.1 released
     
     commit 3628164fb26d48395383f8f31179f24e0882e1e0
     Author: Brian <brian@toimc.com>
     Date:   Tue Aug 20 15:11:49 2013 +0800
     
     append GPL
    

    还可以通过-s用私钥签名一个标签:

     $ git tag -s v0.2 -m "signed version 0.2 released" fec145a
    

    参考资料:

    GPG入门教程

    带GPG签名的Git tag

    git使用GPG进行签名

  2. 标签操作(删除,推送)

    命令git push origin <tagname>可以推送一个本地标签;

    命令git push origin --tags可以推送全部未推送过的本地标签;

    命令git tag -d <tagname>可以删除一个本地标签;

    命令git push origin :refs/tags/<tagname>可以删除一个远程标签。

    如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:

     $ git tag -d v0.9
     Deleted tag 'v0.9' (was 6224937)
    

    然后,从远程删除。删除命令也是push,但是格式如下:

     $ git push origin :refs/tags/v0.9
     To git@github.com:michaelliao/learngit.git
      - [deleted]         v0.9
    

使用.gitignore忽略文件

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files …,有强迫症的童鞋心里肯定不爽。

好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore

忽略文件的原则是:

  • 忽略操作系统自动生成的文件,比如缩略图等;
  • 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
  • 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

举个例子:

假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:

# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini

然后,继续忽略Python编译产生的.pyc.pyodist等文件或目录:

# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build

加上你自己定义的文件,最终得到一个完整的.gitignore文件,内容如下:

# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini

# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build

# My configurations:
db.ini
deploy_key_rsa

最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说working directory clean。

使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。

或者可以使用以下方法,在git bash中输入以下命令:

$ touch .gitignore
$ vi .gitignore

Git忽略规则及.gitignore规则不生效的解决办法:

git rm -r --cached .
git add .
git commit -m 'update .gitignore'

PS:注意–cached后面有一个”.”,add后面也有一个“.”

完成上述操作后,再重新修改.gitnore文件,并git add .添加文件到缓存区

配置命令别名

有没有经常敲错命令?比如git status?status这个单词真心不好记。

如果敲git st就表示git status那就简单多了,当然这种偷懒的办法我们是极力赞成的。

我们只需要敲一行命令,告诉Git,以后st就表示status

$ git config --global alias.st status

好了,现在敲git st看看效果。

当然还有别的命令可以简写,很多人都用co表示checkoutci表示commitbr表示branch

$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch

以后提交就可以简写成:

$ git ci -m "bala bala bala..."

--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用。

在撤销修改一节中,我们知道,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区。既然是一个unstage操作,就可以配置一个unstage别名:

$ git config --global alias.unstage 'reset HEAD'

当你敲入命令:

$ git unstage test.py

实际上Git执行的是:

$ git reset HEAD test.py

配置一个git last,让其显示最后一次提交信息:

$ git config --global alias.last 'log -1'

这样,用git last就能显示最近一次的提交:

$ git last
commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2
Merge: bd6ae48 291bea8
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Thu Aug 22 22:49:22 2013 +0800

merge & fix hello.py

甚至还有人丧心病狂地把lg配置成了:

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

来看看git lg的效果:

为什么不早点告诉我?别激动,咱不是为了多记几个英文单词嘛!

配置文件

配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:

$ cat .git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = git@github.com:michaelliao/learngit.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[alias]
    last = log -1

别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:

$ cat .gitconfig
[alias]
    co = checkout
    ci = commit
    br = branch
    st = status
[user]
    name = Your Name
    email = your@email.com
    

Git恢复流程

当中心仓库由于不可抗拒因素而垮了之后:

项目Git恢复流程:

方法一:恢复指定分支

1.注册账号→输入SSH keys→新建项目。

2.在原项目文件夹下,使用git remote -v命令查看

$ git remote -v
origin  git@192.168.1.222:kanlidy/HelloGit.git (fetch)
origin  git@192.168.1.222:kanlidy/HelloGit.git (push)

使用git remote remove origin删除原有仓库地址。

3.使用新的仓库地址:

git remote add origin [ssh仓库地址]

如:

git remote add origin ssh://git@github.com/kanlidy/HelloGit.git

4.添加文件,并Commit提交,最后push上远程指定分支

git add .

git commit -m "add my repo"

#这条命令会把当前分支,推送到远程的master分支
git push origin master 

#如果需要把dev分支,推送到远程的dev分支
git push origin dev:dev

方法二:恢复项目所有分支:

git remote remove origin

git remote add origin [新的SSH仓库地址]

git push --mirror ssh://git@github.com/kanlidy/LearnPython.git

本地多个SSH密钥文件

有的时候,不仅github使用ssh key,工作项目或者其他云平台可能也需要使用ssh key来认证,如果每次都覆盖了原来的id_rsa文件,那么之前的认证就会失效。这个问题我们可以通过在~/.ssh目录下增加config文件来解决。

  1. 第一步依然是配置git用户名和邮箱

     git config user.name "用户名"
     git config user.email "邮箱"
    
  2. 生成ssh key时同时指定保存的文件名

     ssh-keygen -t rsa -f ~/.ssh/id_rsa.company -C "email"
    

    上面的id_rsa.company就是我们指定的文件名,这时~/.ssh目录下会多出id_rsa.companyid_rsa.company.pub两个文件,id_rsa.company.pub里保存的就是我们要使用的key。

  3. 新增并配置config文件

    添加config文件

    如果config文件不存在,先添加;存在则直接修改

     touch ~/.ssh/config
    

    在config文件里添加如下内容(User表示你的用户名)

     Host 域名或者IP
         IdentityFile ~/.ssh/id_rsa.company
         User test
    

    如:

     Host 192.168.1.222
     IdentityFile ~/.ssh/id_rsa.company
     User kanlidy
    
  4. 上传key到云平台后台(省略)

  5. 测试ssh key是否配置成功

      ssh -T git@域名或者IP
    

    如:

      ssh -T git@192.168.1.222 -p 8082
    

    成功的话会显示:

      Welcome to GitLab, kanlidy!
    

    至此,本地便成功配置多个ssh key。日后如需添加,则安装上述配置生成key,并修改config文件即可。