Git是一个极其优秀的分布式版本控制系统。该系统可以记录用户文件的每一次变动,还具有强大的团队协同工作能力,每个人都可以提交对文本的改动,而不必担心会覆盖他人的操作。Github更是一个通过Git进行版本控制的软件源代码托管服务。截至到2015年,Github已经有超过九百万注册用户和2110万代码库。Github已经成为了世界上最大的代码存放网站和开源社区。

GIT使用教程

创建版本库

选择一个合适的地方,创建一个空目录

mkdir <dir-name>
cd <dir-name>  #在仓库中进行操作
pwd  #可查看当前目录
git init #将目录变为Git可以管理的仓库,即初始化仓库

之后会在当前目录下产生一个.git的目录,该目录是Git用来跟踪管理版本库,也可以选用一个非空目录创建Git仓库

编写保存文件

编写文件并存放至<dir-name>目录下(或子目录)

用纯文本方式编辑并保存文件,文件编码格式保存为UTF-8编码格式

git add <filename1> <filename2> ...  #告知Git将文件添加至仓库
git commit -m "..."  #将文件提交到仓库 -m后面输入本次提交的说明,可以一次提交多个文件
git status  #可查看仓库当前的状态,告知用户是否有文件被修改
git diff  #查看文件具体修改了什么,或对比文件
git log  #显示从最近到最远的提交日志(可加上参数--pretty=oneline改变显示视图)
git reset --hard HEAD^  #文件回退至上一版本

Git中,用HEAD表示当前版本,上一版本就是HEAD^,上上版本为HEAD^^,往上N个版本可写为HEAD~N

git reset --hard <fileID>  #文件版本跳至版本ID为<fileID>的文件
git reflog  #记录用户的每一次操作,可借由此查看文件回退前的版本号

工作区与暂存区

  • 工作区

在计算机里可以看到的目录就是工作区,用于存放文件

  • 版本库与暂存区

工作区下有一个隐藏目录.git,这个是git的版本库,版本库里存有暂存区(stage/index)

  • Git大致工作原理

文件添加至Git版本库分为两步:

  1. git add将文件添加进暂存区,即把对文件的修改或相关操作添加到暂存区
  2. git commit提交更改,即把暂存区的全部内容提交到当前分支

文件撤销操作

git checkout -- <filename> 将在工作区的修改全部撤销,命令--很重要,没有--就变成了切换到另一个分支的命令

文件撤销情况

关于文件需要撤销操作的,大致有两种情况:

  • <filename>自修改后还没放到暂存区,则命令执行后文件撤销修改就回到和版本库一模一样的状态
  • <filename>已经添加到暂存区后,又作了修改,则命令执行后文件撤销修改就回到添加到暂存区后的状态 总之,就是让文件回到最近一次git commit或git add时的状态

撤销与回退小结

  1. 当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令 git checkout -- <filename>
  2. 当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步:用命令 git reset HEAD <filename>,就回退到1中,然后继续1的操作
  3. 当你已经提交了不合适的修改到版本库时,想要撤销本次提交,可参考版本回退,不过前提时没有推送到远程库

版本回退:git reset --hard <ID>,将文件跳至版本号ID的文件,HEAD表示最新的文件版本

Git撤销删除

Git中删除也是一种修改操作

一般情况下,在提交至版本库后,我们直接在文件管理器中删除文件(或通过rm命令),git status会告知那些文件被删除,这时有两种选择:

  1. 确实要从版本库中删除,可执行git rm命令删除,并git commit
  2. 手误删除文件,这时可执行git checkout -- <filename>命令把误删的文件恢复到最新版本
  • git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以"一键还原", 命令git rm用于删除一个文件,如果一个文件已经被提交到版本库,那永远不用担心误删,但你只能恢复文件到最新版本,你会丢失最近一次修改提交后的内容

创建SSH Key

ssh-keygen -t rsa -C "youremail@example.com"

创建后,可在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个文件就是SSH Key的秘钥对,id——rsa是私钥,不能泄露,id_rsa.pub是 公钥,可以公布。之后登陆Github进行设置,进入"SSH Key"页面,点击"Add SSH Key",填上任意标题,在Key文本框里粘贴id_rsa.pub文件里的内容

Github允许添加多个Key

关联远程库

首先在Github上新建一个仓库(或者使用已有的仓库),在本地的一个仓库中运行以下命令:

git remote add origin git@github.com:<accountname>/<localreponame>.git

添加后,远程库名字Git默认为origin,可以更改:

git push -u origin master

git push命令,实际是把当前分支master推送到远程, 如果这是你第一次推送master分支,你需要加上-u参数,Git不但会把本地的master分支内容推送到远程的新的master分支,还会把本地的master分支和远程的master分支关联起来, 在以后的推送或者拉取时可简化命令,之后只要本地作了提交,就可以通过命令:git push origin master完成提交 在第一次使用Git的clone或push命令时会得到一个SSH警告,输入yes即可

#关联一个远程库
git remote add origin git@server-name:path/repo-anme.git

克隆远程库到本地

在Github中新建库后,可以使用git clone克隆一个本地库 git clone git@github.com:<git库地址>

Git支持多种协议,包括https

windows系统:git clone <Git远程库的url>

Git分支

git branch  #查看分支
git branch <name>  #创建分支
git checkout <name>  #切换分支
git checkout -b <name>  #创建+切换分支
git merge <name>  #合并某分支到当前分支
git branch -d <name>  #删除分支

多个分支是共用暂存区,即如果在分支1上仅add而不commit,实际暂存区中已经记录该次修改,哪怕之后切换到分支2上再进行commit也是有效操作 当Git无法自动合并分支时,需要首先解决冲突。解决冲突后再提交, 用git log --graph命令可以看到分支合并图,git status也可以查看冲突的文件

e.g:git log --graph --pretty=oneline --abbrev-commit

Git分支管理

合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出曾经做过合并,而fast-forward合并就看不出曾经做过合并

git merge --no-ff -m"..." <name>

以普通方式合并分支(即禁用fast forward)因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去`

分支策略:

  • 在实际开发中,我们应该按照几个基本原则进行分制管理:
  • master分支应该是非常稳定的,也就是仅用来发布新版本,平时不在上面干活;
  • 干活都在dev分支,即devd分支是不稳定的,到某个时候,再把dev分支合并到master分支上;
  • 每个人都在dev分支上工作,每个人都有自己的分支,要保存时往dev分支上合并就可以了

Bug分支

git stash命令相当于对当前工作环境做一个快照,等以后恢复环境后继续工作

在哪个分支上修复bug,就在从哪个分区创建临时分支

修复完后再提交并删除分支

git stash list  #查看是否存在stash
git stash apply  #恢复stash内容,该命令执行后并不删除stash内容
git stash drop  #删除stash内容
git stash pop  #恢复stash内容,在恢复的同时也删除内容

修复Bug时,当手头工作没有完成时,先把工作现场git stash一下,然后再去修复Bug,修复后,再git stash pop回到工作现场

Feature分支(添加新功能)

在开发新功能时最好新建一个分支, 若要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除

多人协作

git remote查看远程库的信息

git remote -v查看远程库详细的信息(上面显示了抓取和推送的<远程库名字>的地址,如果没有推送权限,就看不到push的地址)

  • 推送分支:

推送分支就是把该分支上的所有本地提交推送远程库。推送时,要指定本地分支

git push <远程库名字> <本地库名字>
git pull  #把最新的提交从远程库中抓取下来

抓取后在本地合并并解决冲突后再推送

  • 工作模式:
  1. 首先,可以试图用git push origin branch-name推送自己的修改
  2. 如果推送失败,则因为远程分支比你的本地版本新,需要先用git push试图合并
  3. 如果合并有冲突,则解决冲突,并在本地提交
  4. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功

如果git pull提示"no tracking information",则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name(该命令用于建立本地分支和远程分支的关联)

标签管理

发布一个版本时,我们通常先在版本库中打一个标签tag,这样,就唯一确定了打标签时的版本。在将来的某个时候,取某一个标签的某一版本,就是把那个打标签的时刻对应的版本取出。标签也是版本库的一个快照

Git标签虽然是版本库的快照,但其实它是指向某个commit的指针(分支可以移动,标签不能移动)

Tag就是一个让人容易记住的名字,它与某个commit绑定在一起

git tag <name>  #在git中打标签应先切换至需要打标签的分支
git tag  #查看所有标签默认标签是打在最新提交的commit上的
git tag <name> <commit ID>  #给对应ID的commit打上标签

标签不是按时间顺序列出,而是按字母排序的,可以用git show <tagname>查看标签信息

git tag -a <tagname> -m "..."  #创建带说明的标签,-a指定标签名,-m指定说明文字
git tag -d <tagname>  #删除本地标签,因为创建的标签都只储存在本地,不会自动推送至远程
git push <远程库名字> <tagname>  #推送某个标签到远程
git push <远程库名字> --tags  #一次性推送全部尚未推送到远程的本地标签

其中在上面第一行代码中若用参数-s替换-a则可以用PGP签名标签

已推送到远程的标签的删除:

git push <远程库名字> :refs/tags/<tagname>

在Github上,可以任意Fork开源仓库;

自己拥有Fork后的仓库的读写权限;

可以推送Pull request给他人仓库来贡献代码;

Fork他人仓库之后再在自己的账号下clone仓库,这样才能推送修改

自定义Git

git config --global color.ui true  #git会适当显示不同的颜色
  • 忽略文件

在Git工作区的根目录下有一个.gitignore文件(没有可创建),然后把要忽略的文件名填进去,Git就会自动忽略这些文件

忽略文件的原则:

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

之后将.gitignore也提交到Git,就完成了忽略文件设置

git check-ignore  #检查.gitignore文件
git add -f <filename>  #强制添加文件

我们可以对.gitignore进行版本管理

  • 设置别名

git config --global alias <别名> <命令原名> –global参数是全局参数,也就是这些命令在电脑的所有Git仓库下都有效

配置Git时,加上--global是针对当前用户启作用,如果不加,则只针对当前仓库起作用。 每个仓库的Git配置文件都放在.git/config文件中, 别名在[alias]后面,删除别名则直接删除对应行即可。 当前用户的Git配置文件在用户主目录的一个隐藏文件.gitconfig中

搭建Git服务器(linux ubuntu or debian)

  1. 安装git:sudo apt-get install git;
  2. 创建一个git用户,用来运行git服务:sudo adduser git;
  3. 创建证书登录:收集所有需要登录的用户的公钥,即他们的id_rs.pub文件,将所有公钥导入到/home/git/.shh/authorized_keys文件中(可改名);
  4. 初始化Git仓库:sudo git init --bare <reponame>;参数–bare为创建一个裸仓库,即没有工作区(服务器上的Git仓库通常都以.git结尾,创建后把owner改为git sudo chown -R git:git <reponame>;
  5. 禁用shell登录:出于安全考录,2中创建的git用户不允许登录shell,可通过编辑/etc/passwd文件实现 找到类似一行:git:x:1001:1001:,,,:/home/git:/bin/bash 改为:git:x:1001:1001:,,,:/home/git:/usr/bin/got-shell 这样当用户用shell登录时会自动退出;
  6. 克隆远程仓库:git clone git@server:/srv/<reponame>;在各自的电脑中运行

参考:

廖雪峰的Git教程