Git 教程

1. 安装Git

Git是目前世界上最先进的分布式版本控制系统。能自动记录每次文件的改动,还可以多人协作编辑同一项目。
参考:廖雪峰Git教程
安装: sudo apt-get install git

配置git信息
因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。

git config --global user.name "username"
git config --global user.email "email"

--global参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

2. Git版本库

创建版本库

版本库又名仓库,英文名repository。可以简单理解成一个目录,这个目录里面每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
初始化一个Git仓库:

mkdir myProgect # 创建一个项目文件夹 
git init  # 初始化仓库

git init命令把这个目录变成了一个Git可以管理的仓库。可以发现当前目录下多了一个.git目录,这个目录是Git来跟踪管理版本库的,千万不要手动修改这个目录里面的文件。

工作区和暂存区

前面创建的项目文件夹myProject就是工作区

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库(Repository)。
.git中最重要的就是称为stage(或者叫index)的暂存区。还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。在这里插入图片描述

Git命令必须在Git仓库目录内执行(git init除外),在仓库目录外执行是没有意义的。

git只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件内容的变化,只知道图片从100KB改成了120KB。

在版本库添加文件或提交修改

添加文件提交修改的命令是一样的,需要如下两步:

git add readme.txt  # 将readme.txt添加到版本库
git commit -m "wrote a readme file"  # 告诉Git,把文件提交到仓库,-m后面输入的是本次提交的说明

注意添要加到版本库的文件一定是放在版本库文件夹内的(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。

commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

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

每次commit,都会存盘当前版本。

为什么Git添加文件需要add,commit一共两步呢?

前面讲了git的工作区和暂存区概念。
第一步用git add添加文件,实际上就是把文件修改添加到暂存区;
第二步用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
你可以简单理解为,先把需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

查看修改

git status 查看仓库当前的状态,如果没有修改任何内容,无需进行提交,会显示:

On branch master
nothing to commit, working tree clean

如果文件被修改过,可以git diff xxx.xx查看文件做了什么修改(即当前工作区的文件和版本库中的该文件的最新版本的区别),确认无误后就可以用add,commit两步提交修改了。

版本回退

git log:显示从最近到最远的提交日志。如果嫌输出信息太多,眼花缭乱,可以加上--pretty=oneline参数。友情提示:你看到的一大串类似1094adb…的是commit id(版本号)。

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

git reset --hard HEAD^  # 回退到上一版本

如果回退一个版本后,又想回到之前的最新版怎么办?
只要上面的命令行窗口还没有关闭就还可以拯救。找到想要回退的版本的commit id,如1094adb…就可以回到未来了:

git reset --hard 1094a  # 版本号没必要写全,前几位就可以了,Git会自动去找

如果命令窗口关了,找不到版本号,也不要慌。
git reflog记录了你的每一次命令。

撤销修改
git checkout -- readme.txt  # 命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令

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

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

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

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

如何把暂存区的修改撤销掉(unstage)呢?需要两步:

git reset HEAD readme.txt  # 把暂存区的修改撤销掉, 重新放回工作区
git checkout -- readme.txt # 丢弃工作区的修改
删除文件
rm test.txt  # 先删除工作区的文件
# 然后推送到版本库
git rm test.txt  # 此时,git rm <file>和git add<file>效果是一样的
git commit -m "remove test.txt"  

#如果删错了就撤销修改
git checkout -- test.txt

3. 远程仓库

Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。

怎么分布呢?实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。

自己找个电脑搭建Git服务器有点小题大做,好在Github网站提供Git仓库托管服务的,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。

由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要设置SSH Key:

1.创建SSH Key

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

然后一路回车。用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

2.设置github
登陆GitHub,Settings - SSH Keys - Add SSH Key,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:

在这里插入图片描述

为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

添加远程仓库

创建一个GitHub远程仓库,然后将本地Git仓库与GitHub远程仓库同步。

在github 选“New repository”。创建一个新仓库。
在Repository name填入仓库名myProject,其他保持默认设置,点击“Create repository”按钮,就成功地创建了一个新的Git仓库。

现在我们可以把一个自己的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。

在本地的myProject仓库下运行命令:

git remote add origin git@github.com:GitHub账户名/myProject.git

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

把本地库的所有内容(实际上是当前分支master)推送到远程库上:

git push -u origin master  

第一次推送master分支时,为了把本地的master分支和远程的master分支关联起来, 加上了-u参数。在以后的推送或者拉取时就可以简化命令。

从现在起,只要本地作了提交,就可以通过命令:

git push origin master

把本地master分支的最新修改推送至GitHub。

你也可以将一个本地仓库链接多个远程仓库,
例如:添加码云(gitee)上的仓库,为了区分,将gitee上的远程仓库代称取为gitee:

git remote add origin git@github.com:GitHub账户名/myProject.git
git remote add gitee git@gitee.com:账户名2/myProject.git

# 将本地master推送到不同的远程仓库
git push origin master
git push gitee master
删除远程库

此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。

# 建议先查看远程库信息
git remote -v
# 然后,根据名字删除,比如删除origin
git remote rm origin
从远程库克隆
git clone git@github.com::GitHub账户名/myProject.git  # 克隆master分支
git clone -b dev git@github.com::GitHub账户名/myProject.git  # 克隆dev分支
git clone -b <远程指定分支> <远程仓库地址> <本地文件夹名>  # 克隆指定分支,并重命名

Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。ssh协议速度最快。

3. 分支管理

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
这时你就需要创建一个属于自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

创建与合并分支

每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。Git为我们自动创建的第一个分支称为master分支。

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支 (HEAD指向的就是当前分支),以及当前分支的提交点:

在这里插入图片描述

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

在这里插入图片描述
你看,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
在这里插入图片描述

git branch  # 查看分支
git branch <name>  # 创建分支
git branch -d <name>  # 删除分支

git checkout <name>  # 切换分支, 或者 git switch <name>
 git checkout -b <name>  # 创建+切换分支, 或者 git switch -c <name> 

git merge <name>  # 合并某分支到当前分支
解决冲突

master分支和feature1分支各自都分别有新的提交,变成了这样:

在这里插入图片描述
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:

git merge feature1

会返回:Automatic merge failed; fix conflicts and then commit the result.
Git告诉我们文件存在冲突,必须手动解决冲突后再提交。
git status 查看冲突内容。

Bug分支

每个bug都可以在一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上的工作只进行到一半,还没法提交,怎么办?
Git提供了一个git stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作。

git stash  # 保存现场
git checkout master  # 切换到要修复bug的分支,此时假设我们要修复master分支上的bug
git switch -c  issue-101  # 从master分支创建issue-101分支

# 修复bug后推送到issue-101 
git add xxx.xx
git commit -m "fix bug 101"

git switch master  #切换回master分支
git merge --no-ff -m "merged bug fix 101" issue-101  # 合并分支。--no-ff 在这的作用是禁止快进式合并。-m "merged bug fix 101" 是版本说明
git branch -d  issue-101  # 删除 issue-101 分支

git switch dev # 切换回dev分支
git stash pop  # 恢复现场,同时删除stash的内容

# 或者分两步
git stash apply  # 恢复现场
git stash drop # 删除stash的内容

你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:git stash apply stash@{0}

在master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。

同样的bug,要在dev上修复,我们只需要把4c805e2 fix bug 101这个提交所做的修改“复制”到dev分支。

git cherry-pick 4c805e2
Feature分支

添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。

例如,你现在要开发代号为Vulcan的新功能。

git switch -c feature-vulcan  # 创建分支
git add vulcan.py  # 提交修改
git switch dev  # 切回dev分支,准备合并
git merge  feature-vulcan # 合并feature-vulcan 分支到dev分支
git branch -d feature-vulcan  # 删除分支。没有被合并的分支可以用大写 -D 参数强行删除。 
多人协作
  • 查看远程库信息,使用git remote -v
  • 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致。
  • 本地新建的分支如果不推送到远程,对其他人就是不可见的。

推送分支

  • master分支是主分支,因此要时刻与远程同步;
  • dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
  • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
  • feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin <branch-name>推送自己的修改;

  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull把最新的提交抓下来,试图合并。

  3. 如果合并有冲突,则解决冲突,并在本地提交;

  4. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

  5. 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

debug

git clone 报错
fatal: unable to access … server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none

解决方法:

切换网络
export GIT_SSL_NO_VERIFY=1
可能还需要
ssh-agent bash
ssh-add ~/.ssh/id_rsa.pub
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值