Git 学习笔记

1.Git是什么?

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

2.什么是版本控制系统?

顾名思义,控制文件的多个版本,可以理解为,自动记录文件在什么时候被谁进行了怎样的更改。

3.如何安装Git?

我用的Windows系统,使用国内镜像下载任一版本 https://npm.taobao.org/mirrors/git-for-windows/
一路默认进行安装即可,安装完成后在开始菜单找到"Git->Git Bash",蹦出一个下面这样的窗口,就说明Git安装成功。

4.安装完成后,可以用 git --version 来查看 Git 版本。然后设置名字和邮箱。

在命令行输入:
$ git config --global user.name "Your Name"          
$ git config --global user.email "email@example.com"

5.创建仓库

仓库又称版本库,可以理解为一个目录,这个目录里面的所有文件都可以被Git管理起来。
mkdir learngit    //创建目录learngit
cd learngit    //转到目录learngit下
pwd    //用于显示当前目录
git init    //把这个目录变成Git可管理的仓库

6.把文件添加到版本库

首先,通过 vi readme.txt 命令编写文件 readme.txt,按 i 开始编写,写完之后按 Esc,然后按shift+zz 退出文本编辑页面。
其次,把一个文件放到 Git 仓库只需两步,第一步把文件添加到仓库暂存区 stage
,用 git add filename, 如 git add readme.txt第二步把文件提交到仓库第一个分支 master,用 git commit -m "本次提交的说明" ,如 git commit -m "wrote a readme file" 。

可以多个add之后,用一个commit。

可以用 git status 来查看仓库当前状态。

可以用 git diff filename 来查看文件具体修改了什么内容。

7.版本回退

git log 来查看一个文件每次修改的提交情况,会显示从最近到最远的提交日志。
可以使用 git log --pretty=oneline 来简化输出的日志信息。
前面的一串十六进制序列是 commit id 即版本号。
在 git 中,用 HEAD 来表示文件的当前版本,上一个版本是 HEAD^,上上一个版本是 HEAD^^,往上100个版本是 HEAD~100。

可以使用 git reset --hard HEAD^ 从当前版本回退到上一个版本。

可以根据版本号指定回到未来的某个版本。版本号没必要写全,只写前几位就可以了,Git会自动查找。如,git reset --hard 14e8d

Git 的版本回退速度非常快,因为 Git 在内部有个指向当前版本的 HEAD 指针,当你回退版本的时候,Git 仅仅是改变 HEAD 指针的指向,顺便把工作区的文件更新。

Git 提供命令 git reflog 用来记录每一次命令,可以查看命令历史。

8.管理修改

Git 跟踪并管理的是修改,而非文件。
第一次修改 -> git add -> 第二次修改 -> git commit
第一次的修改被提交了,第二次的修改不会被提交。
第一次修改 -> git add -> 第二次修改 -> git add -> git commit
第一次第二次的修改都会被提交。
说明:每次修改,如果不用git add到暂存区,那就不会加入到commit中。

 

 

 

9.撤销修改

用 git restore -- filename 可以撤销修改(还没add)
用 git restore --staged filename 可以撤销提交(add之后,还没commit)。
如果 commit 了,只能进行版本回退了。

 

10.删除文件

先添加文件 test.txt 到 Git 并提交,用 rm 命令删除 rm test.txt,这时工作区和版本库不一致,有两个选择,一是可以用 git rm test.txt 从版本库中删除该文件,并且 git commit。 二是删错了,此时因为版本库里还有,可以把误删的文件恢复到最新版本 git restore -- test.txt

 

11.远程仓库

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

一般找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库拉取别人的提交。

首先,注册一个 GitHub 账号。

其次,由于本地 Git 仓库和 GitHub 仓库之间的传输是通过 ssh 加密的,所以需要设置一下:第一步创建 SSH key。在用户主目录下通过命令 ls -sh 查看有没有.ssh 目录,如果有,再看看这个目录下有没有 id_rsa 和 id_rsa.pub 这两个文件,这两个就是 SSH Key 的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。如果有,跳过这一步,如果没有,通过命令   ssh-keygen -t rsa -C "youremail@example.com" 创建 SSH key,然后一路回车。可以通过命令  ssh -T git@github.com 来检查是否成功,输入 yes,会看到提示成功认证。第二步:登陆 GitHub,右上角找到 setting,找到 SSH keys,填上任意 Title,在 Key 文本框里粘贴 id_rsa.pub 文件内容,点击 Add key 即可。

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

GitHub 允许添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的 Key 都添加到 GitHub,就可以在每台电脑上往 GitHub 推送了。

12.添加远程库

假设已经在本地创建了一个 Git 仓库 learngit,又想在 Github 创建一个 Git 仓库,并且让这两个仓库进行远程同步。这样,GitHub 上的仓库既可以作为备份,又可以让其他人通过该仓库来协作。

第一步:登陆 Github,右上角找到 New repository,输入仓库名 learngit,点击 Create repository
就成功创建了一个新的Git仓库。根据 Github 的提示进行之后的操作,在本地仓库下运行命令
git remote add origin git@github.com:ZYXerhe/learngit 关联远程库。

第二步:通过 git push 命令 git push -u origin master 就可以把本地库的所有内容推送到远程库上,实际上是把当前分支 master 推送到远程。推送成功后,可以立刻在 GitHub 页面中看到远程库的内容已经和本地一模一样。

从现在起,只要本地做了提交,就可以通过命令:git push origin master 把本地 master 分支的最新修改推送至 GitHub。

13. 删除远程库

如果添加的时候地址写错了,或者就是想删除远程库,可以git remote rm <name> 命令。使用前,建议先git remote -v (加 -v 更详细)查看远程库信息


然后,根据名字删除,比如删除 origin:git remote rm origin

此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到 GitHub,在后台页面找到删除按钮再删除。

14.Git 好处之一

在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,当有网络的时候,再把本地提交推送一下就完成了同步。

15.从远程库克隆

假设本地没有仓库,先在 GitHub 上创建远程库,然后从远程库克隆到本地。

首先,登陆 GitHub,创建一个新的仓库,输入仓库名 gitskills,勾选 Add a README file 后点击Create repository,GitHub 会自动为我们创建一个 README.md 文件。创建完毕后,可以看到README.md文件。
然后,用命令 git clone 克隆一个本地库 git clone git@github.com:ZYXerhe/gitskills ,然后在本地进入 gitskills 目录查看,发现已经有 README.md 文件了。

16.分支管理

在团队合作开发的项目中,当你自己的项目只完成一半,不能全部提交又担心丢失进度修改的情况下,可以创建一个仅属于你自己的分支,其他人看不到,这样,其他人就在原来的分支上正常工作,而你在自己的分支上工作,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

17.创建与合并分支

在 Git 里,有一个主分支 master,用 HEAD 指向 master,用 master 指向提交,HEAD 指向的是当前分支。

理论部分:

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

git-br-initial

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

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

git-br-create

Git 创建一个分支很快,除了增加一个 dev 指针,改一下 HEAD 的指向,工作区的文件没有任何变化。

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

git-br-dev-fd

假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。最简单的方法,就是直接把master 指向 dev 的当前提交,就完成了合并。所以 Git 合并分支也很快,就改改指针,工作区内容也不变。

git-br-ff-merge

合并完分支后,可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,就剩下了一条 master 分支:

git-br-rm

下面是实战:

首先,创建 dev 分支,然后切换到 dev 分支。通过命令 git checkout -b dev 或 git switch -c dev 完成。也可以通过两条命令 git branch dev   创建分支   ② git checkout dev  或 git switch dev 切换分支 来完成。
然后,git branch 命令查看所以分支,当前分支前面会带 * 号。
接着,在 dev 分支上修改 readme.txt 并提交。
现在,dev 分支工作完成,用命令 git checkout master 切换回 master 分支。
查看 readme.txt 会发现并未看到刚才对该文件的修改!这是因为,刚才的提交是在 dev 分支,而 master 分支此刻的提交点并没有变。 

git-br-on-master

现在,用命令 git merge dev 把 dev 分支的工作成果合并到 master 分支上。
合并后,查看 readme.txt 发现和 dev 分支的最新提交是完全一样的。
注意到下面的 Fast-forward 信息,Git告诉我们,这次合并是“快进模式”,也就是直接把 master 指向 dev 的当前提交,所以合并速度非常快。

合并完成后,就可以用命令 git branch -d dev 放心地删除dev分支了。
此时,用 git branch 查看分支就只剩 master 了。

18.解决冲突

进入 learngit 仓库,创建并切换到新分支 feature1,修改 readme.txt 最后一行为:Creating a new branch is quick AND simple. 并在 feature1 分支上提交,提交成功后切换到 master 分支,在 master 分支上把 readme.txt 最后一行修改为:Creating a new branch is quick & simple. 并在 master 分支上提交。

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

git-br-feature1

这种情况下,Git 无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突。

Git 告诉我们,readme.txt 文件存在冲突,必须手动解决冲突后再提交。git status 也可以告诉我们冲突的文件: 

直接查看 readme.txt 的内容如下:

现修改 readme.txt 最后一行为:Creating a new branch is quick and simple. 并提交。

现在,master 分支和 feature1 分支如下图所示:

git-br-conflict-merged

至此,合并处理完成,最后,删除 feature1 分支:

工作完成! 

总结: 解决冲突就是把 Git 合并失败的文件手动编辑为我们希望的内容,再提交。

19.分支管理策略

通常,合并分支时,Git 会用 Fast forward 模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁止 Fast forward 模式,Git 就会在合并时生成一个新的 commit,这样,从分支历史上就可以看出分支信息。

git merge 加上 --no-ff 参数表示禁用 Fast forward。
git log 加上 --graph 参数可以看到分支合并图。

首先,创建并切换到 dev 分支,修改 readme.txt 并在 dev 分支下提交,提交成功后切换回 master 分支,使用命令 git merge --no-ff -m "merge with no-ff" dev 合并 dev 分支,因本次合并要创建一个新的 comit,所以加上 -m 参数,把 commit 描述写进去。
合并后,用 git log 可查看分支历史

可以看到,不使用 Fast forward 模式,merge 后如图:

git-no-ff-mode

总结:在实际开发中,master 分支应该是非常稳定的,仅用来发布新版本,平时不在这个分支上工作,而在 dev 分支上工作,故 dev 分支不稳定,大家都在 dev 分支上工作,每个人都有自己的分支,时不时地往 dev 分支上合并,当某个时候,比如发布1.0版本时,再把 dev 分支合并到 master 分支,在 master 分支上发布1.0版本。

20.Bug分支

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

假设当前正在 dev 分支工作,接收到要处理一个 bug,自然需要创建一个新的分支来修复这个 bug,但是,在当前 dev 分支还有部分工作未提交(有的没有 git add,有的没有 git commit),这不是不想提交,而是只进行到一半,没法提交,但是 bug 又需要及时恢复。 

处理方式:
首先,用命令 git stash 保存现场Git 提供 stash 功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作。“储藏”后可用 git status 查看工作区,发现工作区是干净的,这是因为文件被 Git 管理起来了。
其次,修复 bug。需要确定在哪个分支修复 bug,假设需要在 master 分支上修复,就从 master 创建临时分支 git checkout -b issue,修复 bug(更改不正确内容并提交)。
然后,修复完成后,切换到 master 分支,完成合并 git merge --no-ff -m "merged bug fix" issue
最后,删除 issue 分支 git branch -d issue

现在回到 dev 分支,恢复现场。git stash list 命令查看(保存的现场情况)

$ git stash list
stash@{0}: WIP on dev: f52c633 add merge

可知工作现场还在,Git 把 stash 内容存在某个地方了,有两个办法进行现场回复:
①用 git stash apply 恢复,但是恢复后,stash 内容并不删除,需要用 git stash drop 来删除;
②用 git stash pop,恢复的同时把 stash 内容也删了。

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

在 master 分支上修复了 bug 之后,还需要在 dev 分支再次修复,因为 dev 分支是从 master 分支分出来的,所以这个 bug 其实在当前 dev 分支上也存在。

同样的 bug,在 dev 上修复,只需要把修复此 bug 的提交所做的修改“复制”到 dev 分支。(用 git reflog 查看命令历史,设查到为 4c805e2 fix bug 101)

Git 提供命令 cherry-pick 让我们能复制一个特定的提交到当前分支。

假设当前在 dev 分支,用命令 git cherry-pick 4c805e2 即可修复此bug。此时,Git自动给 dev 分支做了一次提交,但这次提交的 commit 是1d4b803,它并不同于 master 的4c805e2,因为这两个commit 只是改动相同,但确实是两个不同的 commit。

21.Feature分支

添加一个新功能时,为了避免主分支混乱,我们常新建一个 feature 分支,在上面开发,完成后,合并,最后,删除该 feature 分支。

例:创建并切换到新分支 feature,开发文件 hello.py 并提交,切换回 dev 分支,正常情况下合并分支并删除即可。但是,如果要求取消该新功能,必须就地销毁。使用命令 git branch -d feature 删除该分支失败,Git 提示该分支还没有被合并,如何删除,将丢失修改,如果要强行删除,需要使用大写的 -D 参数,现在我们用命令 git branch -D feature 强行删除,删除成功。

22.多人协作

(1)用 git remote -v 查看远程仓库信息:

 (2)推送分支

就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:git push origin master。如果要推送其他分支,比如 dev,就改成:git push origin dev

但并不是一定要把本地所有分支都往远程推送:master分支是主分支,要时刻与远程同步;dev分支是开发分支,团队所有成员都需要在上面工作,需要与远程同步;bug分支只用于在本地修复bug,没必要推到远程;feature分支是否推到远程,取决于你是否和你的同事合作在上面开发。总之,在Git中,分支完全可以在本地自己藏,是否推送,全由自己决定!

(3)抓取分支

创建远程 origin 的 dev 分支到本地,用命令 git checkout -b dev origin/dev 创建本地dev分支,在此分支上工作提交并用 git push origin dev 推送自己的修改到远程,如果推送失败,则因为远程分支与你的本地相比进行了更新,需要先用要 git pull (git pull 命令用于从远程获取代码并合并本地的版本)试图合并,如果合并有冲突,则解决冲突,并在本地提交。没有冲突或者解决掉冲突后,再用 git push origin dev 推送就能成功!如果 git pull 提示 no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令设置 dev 和 origin/dev 的链接 git branch --set-upstream-to=origin/dev dev 即可。

23.Rebase

rebase 操作可以把本地未 push 的分叉提交历史整理成直线。
rebase 的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。
在用 git log 之前,先使用命令 git rebase,就可以把原本分叉的提交变成一条直线。
rebase 操作前后,最终的提交内容是一致的,但是,本地的 commit 修改内容已经变化了,但最后的提交内容是一致的。

24.标签管理

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

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

Git有commit,为什么还要引入tag?
因为commit号是一长串乱七八糟的数字不好找,而tag是如v1.2这样的版本号,比commit容易查找太多!所以,tag 就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。

25.创建标签

首先切换到需要打标签的分支上,然后用命令 git tag <name> 就可以打一个新标签
git tag v1.0
可以用命令 git tag 查看所有标签。
默认标签是打在最新提交的 commit 上的,但也可以指定一个 commit id,
git tag v0.9 cc24f81,再用命令 git tag 查看所有标签。
注意,标签不是按时间顺序列出,而是按字母顺序的。
可以用命令 git show <tagname> 查看标签信息,如 git show v0.9。还可以创建带说明的标签,用 -a 指定标签名,-m 指定说明文字,如 git tag -a v0.1 -m "version 0.1" 91936f2。再用 git show v0.1 可以看到说明文字。

注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。

26.操作标签

可用命令 git tag -d v0.1 删除标签。
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令 git push origin <tagname>,如 git push origin v1.0
可以用命令 git push origin --tags 一次性推送全部尚未推送到远程的本地标签。
如果标签已经推送到远程,要删除远程标签,先用命令 git tag -d v0.9 从本地删除,再用
命令 git push origin :refs/tags/v0.9 从远程删除。要看是否真的从远程库删除了标签,需要登陆GitHub查看。

27.使用GitHub

参与开源项目:使用命令 git clone git@github.com:twbs/bootstrap.git(bootstrap的作者的仓库地址)克隆(fork)将因为没有权限而不能推送修改。如果想要推送修改,一定要从自己的账号下克隆仓库,比如用命令 git clone git@github.com:ZYXerhe/bootstrap.git

Bootstrap的官方仓库twbs/bootstrap、你在GitHub上克隆的仓库my/bootstrap,以及你自己克隆到本地电脑的仓库,他们的关系如下图:

如果你想修复 bootstrap 的一个 bug,或者新增一个功能,立刻就可以开始工作,完成后,往自己的仓库推送。
如果你希望 bootstrap 的官方库能接受你的修改,可以在 GitHub 上发起一个 pull request。

28.一个本地库可以既关联GitHub,又关联Gitee。

这是因为Git本身是分布式版本控制系统,可以同步到另外一个远程库,当然也可以同步到另外两个远程库。

使用多个远程库时,要注意,Git 给远程库起的默认名称是origin,如果有多个远程库,需要用不同的名称来标识不同的远程库。
以 learngit 本地库为例,先删除已关联的名为 origin 的远程库:git remote rm origin
然后,先关联GitHub的远程库:git remote add github git@github.com:ZYXerhe/learngit.git
注意,远程库的名称叫github,不叫origin了。
接着,再关联Gitee的远程库:git remote add gitee git@gitee.com:ZYXerhexiu/learngit.git
同样注意,远程库的名称叫gitee,不叫origin了。
现在,用 git remote -v 查看远程库信息,可以看到两个远程库:

git remote -v
gitee    git@gitee.com:ZYXerhexiu/learngit.git (fetch)
gitee    git@gitee.com:ZYXerhexiu/learngit.git (push)
github    git@github.com:ZYXerhe/learngit.git (fetch)
github    git@github.com:ZYXerhe/learngit.git (push)

如果要推送到GitHub,使用命令:git push github master
如果要推送到Gitee,使用命令:git push gitee master

这样一来,本地库就可以同时与多个远程库互相同步:

29.自定义Git

有很多配置,比如,用命令:git config --global color.ui true 让 Git 显示颜色,会让命令输出看起来更醒目。

30.忽略特殊文件

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

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

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

检验 .gitignore 的标准是 git status 命令是不是说 working directory clean。

有些时候,想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:

git add App.class
The following paths are ignored by one of your .gitignore files:
App.class
Use -f if you really want to add them.

如果你确实想添加该文件,可以用 -f 强制添加到 Git:git add -f App.class
可以用 git check-ignore 命令检查 .gitignore 写得是否有问题,如:

git check-ignore -v App.class
.gitignore:3:*.class    App.class

Git会告诉我们,.gitignore 的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。
把指定文件排除在.gitignore 规则外的写法是 !+文件名,如:

# 排除所有.开头的隐藏文件:
.*
# 排除所有.class文件:
*.class

# 不排除.gitignore和App.class:
!.gitignore
!App.class

31.配置别名

git config --global alias.st status        用st表示status
git config --global alias.co checkout        用co表示checkout
git config --global alias.ci commit        用ci表示commit
git config --global alias.br branch        用br表示branch
git status 就可以写为 git st
git commit -m "add ci" 就可以写完 git ci -m "add ci"

--global 参数是全局参数,表示这些命令在这台电脑的所有 Git 仓库下都有用,如果不加,那么只针对当前的仓库起作用。

32.配置文件

每个仓库的 Git 配置文件都放在 .git/config 文件中,可用命令 cat .git/config 进行查看。 发现别名就在 [alias] 后面,要删除别名,直接把对应的行删掉即可。

当前用户的 Git 配置文件放在用户主目录下的一个隐藏文件 .gitconfig中,可用命令 cat .gitconfig 进行查看,配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。

以上!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值