Part 1 Git基本介绍
版本控制基本功能
所有的版本控制系统,只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了什么内容,版本控制系统不知道,也没法知道。
Git优势
- 适合分布式开发,每一个个体都可以作为服务器。每一次Clone就是从服务器上pull到了所有的内容,包括版本信息。
- 公共服务器压力和数据量都不会太大。
- 速度快、灵活,分支之间可以任意切换。
- 任意两个开发者之间可以很容易的解决冲突,并且单机上就可以进行分支合并。
- 离线工作,不影响本地代码编写,等有网络连接以后可以再上传代码,并且在本地可以根据不同的需要,本地新建自己的分支。
- 在本机可以对同一个文件将它进行签出及修改,并在最终签入时,选择保留哪一段代码,如果在同一文件同一行有冲突时,可以对冲突进行选择保留哪一个版本。
- 免费。
Part 2 Git基本操作
本地操作
创建版本库
-
Step 1: 创建项目目录,进入目录。
$ mkdir myproject $ cd myproject
-
Step 2: 初始化本地仓库。
myproject $ git init myproject $ git add . myproject $ git commit -m "add myproject"
提交添加和修改操作
Step 1: 添加项目文件。创建文件
example.txt
,输入文本This is an example.
。-
Step 2: 提交修改。
myproject $ git add example.txt myproject $ git commit -m "add example.txt"
查看仓库状态
-
可以随时查看仓库的状态
myproject $ git status
-
若仓库状态告知有修改,可以使用下属命令查看具体修改内容
myproject $ git diff example.txt
版本退回
-
Step 1: 查看版本记录。使用
--pretty=oneline
参数使显示更简洁。myproject $ git log --pretty=oneline
-
Step 2:
HEAD
表示当前版本,HEAD^
表示上一版本,HEAD^^
表示上上一版本,往上100个版本HEAD~100
。# 退回上一版本 myproject $ git reset --hard HEAD^ # 退回上上一个版本 myproject $ git reset --hard HEAD^^
或者通过
git log
查看提交历史,找到每个版本的commit id
,如xxxxx...
,xxxxx
是commit_id
的前5位,则可以退回到xxxxx...
对应的版本myproject $ git reset --hard xxxxx
若想再次返回到最新版,但却找不到最新版的
commit id
,则使用以下命令查看命令历史myproject $ git reflog
找到最新版本的
commit id
,再次使用git reset --hard commit_id
即可返回最新版本
对比工作区文件与版本库最新版本
-
查看工作区和版本库里面最新版本的区别
myproject $ git diff HEAD -- example.txt
撤销操作
-
Scenario 1: 当改乱了工作区某个文件的内容,想直接丢弃工作区的修改时
myproject $ git checkout -- example.txt
-
Scenario 2: 当不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步
- 使用以下命令回到Scenario 1
myproject $ git reset HEAD example.txt
- 按照Scenario 1中的命令撤销操作
Scenario 3: 在没有推送到远程库而已经提交了不合适的修改到本地版本库时,想要撤销本次提交, 参考版本退回*操作。
删除文件
-
Step 1: 删除文件
myproject $ rm example.txt
-
Step 2.1: 确认删除
myproject $ git rm example.txt myproject $ git commit -m "remove example.txt"
-
Step 2.2: 撤销删除,把误删的文件恢复到最新版本。
myproject $ git checkout -- example.txt
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除
分支管理
-
查看当前分支
$ git branch
-
创建分支
$ git branch <branch_name>
-
切换分支
$ git checkout <branch_name>
-
创建分支并切换
$ git checkout -b <branch_name>
-
删除分支
# 无修改或完成所有提交下 $ git branch -d <branch_name> # 有修改或有未完成的提交,需要强行删除 $ git branch -D <branch_name>
-
合并分支,合并指定分支到当前分支
$ git merge <branch_name>
-
查看分支合并情况
$ git log --graph --pretty=oneline --abbrev-commit
-
普通模式合并。合并分支时,加上
--no-ff
参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。$ git merge --no-ff -m "some infos" <branch_name>
-
储存当前工作区。当前工作尚未提交,但又接到比较紧急的任务,需要储存当前工作区,在完成紧急任务后读取之前储存的工作区,继续工作。
- 储存工作区
$ git stash
- 查看所储存的工作区
$ git stash list
-
恢复工作区
- 恢复后,stash内容不删除,需要手动删除
# 恢复 $ git stash apply # 删除 $ git stash drop
- 恢复切自动删除stash中的内容
$git stash pop
- 若储存了多个工作区,需要先使用
git stash list
查看stash内容,再使用下列命令恢复
git stash apply stash@{0}
解决冲突
在当前分支修改了一文件,在某一分支对同一文件的同一地方做了修改,当把该分支合并到当前分支时,由于是对同一个文件的同一个地方做了修改,会发生冲突。
解决方案:修改当前分支的文件,使其结果与合并后的相同,再提交。
标签管理
-
新建标签
# 默认为HEAD $ git tag <tagname> # 可以指定 commit id $ git tag <tagname> commit_id
-
指定标签信息
$ git tag -a <tagname> -m "some infos"
-
查看所有标签
$ git tag
-
删除标签
# 删除本地标签 $ git tag -d <tagname> # 删除远程仓库标签 $ git tag -d <tagname> $ git push origin :refs/tags/<tagname>
-
推送某个标签到远程
# 推送标签到远程 $ git push origin <tagname> # 推送全部未推送过的本地标签 $ git push origin --tags
忽略特殊文件
当出于保密等需求需要保留一些文件不推送它们时,需要使用忽略特殊文件。
- Step 1: 在项目根目录下新建文件
.gitignore
。 - Step 2: 将需要忽略的文件名或后缀添加在
.gitignore
。
官方标配.gitignore
文件: https://github.com/github/gitignore
-
需要强制加入被忽略的文件
$ git add -f <file>
本地-远程交互操作
与远程库建立联系
-
Step 1: 生成密钥,可以全部设置为默认值。
$ cd ~ $ ssh-keygen -t rsa -C "email@domain.com"
-
Step 2: 复制明码到远程仓库
~ $ cat .ssh/id_rsa.pub
将
id_rsa.pub
中的内容复制,登陆远程仓库如github.com,建立新的密钥,建立完成后可以直接通过命令行推送本地仓库到远程仓库。
添加远程仓库
Step 1: 在远程仓库新建Repository名为
myproject
。-
Step 2: 把一个已有的本地仓库
myproject
与远程仓库的myproject
关联。$ git remote add origin git@github.com:Account/myproject.git
其中,
Account
为Github
账户名,origin
为远程库的默认名字 -
Step 3: 把本地仓库的所有内容推送到远程库上
$ git push -u origin master
使用
git push
命令把当前分支master推送到远程origin中。参数-u
,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来。 Step 4: 完成本地提交后,使用以下命令将本地master分支的最新修改推送至Github
从远程库Clone到本地库
Step 1: 准备好远程库的仓库,如,
account/myproject
。-
Step 2: 将远程库
account/myproject
克隆到本地$ git clone git@github.com: account/myproject
从本地仓库推送(push)到远程仓库
-
已经关联远程库
origin
,需要将本地仓库的分支同步到远程仓库的分支$ git push origin <branch_name>
从远程仓库拉回(pull)到本地仓库
-
已经关联远程库
origin
,需要将远程仓库的分支同步到本地仓库的分支$ git pull origin master
远程仓库操作
-
查看远程仓库名字
$ git remote
-
查看远程仓库详细信息
$ git remote -v
-
删除已关联的远程仓库
# origin为远程仓库名字 $ git remote rm origin
-
关联多个远程仓库。假设当前没有任何关联的远程仓库。
# 先关联Github的远程仓库 $ git remote add github git@github.com: Acount/repository_name.git # 再关联Gitee的远程仓库 $ git remote add gitee git@gitee: Acount/repository_name.git # 推送到Github $ git push github master # 推送到Gitee $ git push gitee master
Part 3 使用Git开发常见工作流
开源多人协作
- Step 1: 选择远程仓库,如github.com,gitee.com等,注册公用账户,新建项目Repository,将本地仓库与远程仓库建立联系,将本地代码推送到远程。详细操作步骤参阅Part 2中的本地-远程交互操作远程库建立联系和添加远程仓库小节。
- Step 2: 每个开发者在相同的远程仓库注册个人账户,将远程仓库Clone到本地库。详细步骤参阅Part 2中的本地-远程交互操作从远程库Clone到本地库小节。
- Step 3: 远程仓库的master分支一般为发行版,或稳定版;新建分支dev为开发版,各个开发者在开发过程中推送本地的dev到远程,项目管理人定期或不定期从dev中更新master。
- Step 4: 开发者试图用
git push origin <branch-name>
推送自己的修改。 - Step 5: 如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull
试图合并;如果合并有冲突,则解决冲突,并在本地提交。 - Step 6: 没有冲突或者解决掉冲突后,再用
git push origin <branch-name>
推送就能成功。 - Step 7: 如果
git pull
提示no tracking information
,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
。
闭源多人协作
与前文开源多人协作的不同之处是,闭源多人协作需要搭建私有Git服务器。搭建Git服务器需要准备一台运行Linux的机器,推荐使用Ubuntu。
-
Step 1: 安装git
$ sudo apt-get install git
-
Step 2: 创建一个git用户,用来运行git服务
$ sudo adduser git
Step 3: 创建证书登录。收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。此步骤原理类似前文本地-远程交互操作中的与远程库建立联系。
-
Step 4: 初始化仓库。选定一个目录作为Git仓库,如
/srv/sample.git
$ cd /srv srv $ sudo git init --bare sample.git # 限制用户直接登录服务器修改仓库 srv $ sudo chown -R git:git sample.git
-
Step 5: 出于安全考虑,禁用shell登陆。编辑/etc/passwd文件完成。找到类似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
修改为
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
则git用户可以正常通过ssh使用git,但无法登录shell。
之后步骤同前开源多人协作中的Step 2~Step 7。
个人开发
个人开发单纯基于本地仓库,不涉及到与远程仓库的交互。
- Step 1: 选择项目目录
myproject
,初始化仓库,详情参阅前文本地操作中的创建版本库。 - Step 2: 其他操作诸如添加、删除、修改新文件、添加新特性、修改bug等参考前文本地操作。
Part 4 参考资料
站在巨人的肩膀上学习。