Git学习

目录

初始化一个Git仓库

添加文件到Git仓库,分为两步

小结

查看状态和文件的修改信息

小结

版本回退

git log查看修改和提交的日志信息

版本回退这里可以使用命令

小结

工作区和暂存区

小结

管理修改

小结

撤销修改

 小结

删除文件

小结

添加远程库

小结

从远程库克隆

小结

分支管理

创建与合并分支

命令

合并分支

 删除分支

switch

小结

 解决冲突

小结

分支管理策略

合并时禁止快速合并模式

小结

bug分支

描述和说明

 小结

参考


初始化一个Git仓库

使用Git init命令

先创建一个目录用来作为一个仓库,使用git init把目录变成Git可以管理得仓库

$git init
Initialized empty Git repository in /Users/michael/learngit/.git/

添加文件到Git仓库,分为两步

第一步,用git add告诉Git,把文件添加到仓库,可以一次性添加多个文件

$git add readme.txt

第二步,用命令git commit告诉Git,把文件提交到仓库

$ git commit -m "wrote a readme file"
[master (root-commit) eaadf4e] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

简单解释一下git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。

首先这里再明确一下,所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。

不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,前面我们举的例子只是为了演示,如果要真正使用版本控制系统,就要以纯文本方式编写文件。

使用Windows的童鞋要特别注意:

千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符,你会遇到很多不可思议的问题,比如,网页第一行可能会显示一个“?”,明明正确的程序一编译就报语法错误,等等,都是由记事本的弱智行为带来的。建议你下载Visual Studio Code代替记事本,不但功能强大,而且免费!

为什么Git添加文件需要addcommit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

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

小结

初始化一个Git仓库,使用git init命令

添加文件到Git仓库,分两步:

1、使用命令git add <file1>  <file2>可以添加多个文件一次性

2、使用命令git commit -m <message>完成,其中message是指提交时的描述信息,帮助你知道这次提交做了什么修改

查看状态和文件的修改信息

如果你想要随时掌握工作区的状态,使用git status命令

如果git status告诉你有文件被修改过,用git diff可以查看修改内容

提交修改和提交新文件是一样的步骤,也是分为两步,第一步是把文件add进仓库中,第二步是commit提交

这里上面输出告诉我们,当前没有需要提交的修改,而且工作目录是干净的。

小结

要随时掌握工作区的状态,使用git status命令

如果git status告诉你有文件被修改过,用git diff可以查看修改的内容

版本回退

 前面的命令是和修改文件后进行添加和提交的,如果不断对文件进行修改,就好比玩游戏存档一样,当你觉得文件修改到一定程度之后,可以“保存一个快照“,这个快照在Git中被称为commit。一旦把文件改乱了,或者误删了文件,可以从最近的一个commit恢复,然后继续工作。

git log查看修改和提交的日志信息

git log命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

 上面的很长一串的数字序列是commit id(版本号)

 其实也可以用git GUI可以明显的看到一些相关的Git版本信息

 其中parent其实就是当前版本的上一个版本,它的child其实就是当前版本的下一个新版本。

版本回退这里可以使用命令

git reset --hard HEAD^

//这里HEAD表示当前版本,也就是最新的版本,上一个版本就是HEAD^,
上上一个版本就是HEAD^^,如果你想回到上一100个版本命令不可能输入
HEAD^^^.....,这时候使用的是HEAD~100
这里的--hard其实就是会把暂存区的恢复到工作区中,git reset HEAD^
只是把版本库回退到了暂存区,但是工作区的文件修改还是保留着,这时
使用git status会提示你未暂存提交的更改

 注意:这里需要注意的是,回到上一个版本容易但是要想再回来就比较难了,因为这里其实可以和C语言的指针作为理解,Git的版本回退速度非常快,因为在Git内部有个指向当前版本的HEAD指针(头指针(个人理解)),当你回退版本的时候,Git仅仅是把HEAD从指向当前版本指向到上一个版本号,但是新版本的没有保存,相当于指针丢失了(野指针)。

 这时候要回到最新版本时,怎么解决呢?好比你从21世纪坐时光机来到了19世纪,想再回去已经回不去了怎么办?

//办法就是只要上面的命令行窗口没有关掉,并且你之前使用过git log
显示版本号信息,这时候你可以找到你要恢复的最新版本的号,这里你可以
使用类似的回退命令

git reset --hard 94ad(这里只需要输入前几位即可,不需要完全输入,
git会自动去找,也不要只写1,2位,怕找到多个一样的,不知道返回哪个)

这时候,git就回到了最新的版本,其实根据这个原理,只需要找到对应的版本号,你可以回退到任何一个版本,回退到对应版本其实顺便把工作区相应的文件也是更新了。

现在你回退到了某个版本,电脑关机,第二天想要回到最新版本这时候怎么办,在Git中,还有后悔药可以吃,总之原理就是找到对应版本的版本号commit id

 Git提供了一个命令,用来记录你的每一次命令:

git reflog

 查找到对应的commit id,你就可以回到对应的版本了。

小结

  • HEAD指向的版本就是当前版本,HEAD^表示上一个版本,HEAD^^上上个版本,HEAD~100上100个版本,使用命令git reset --hard commit_id可以回退到任何版本,原理都是要找到对应的commit_id
  • 所以要查看commit_id就要使用命令git log查看各个版本的日志信息
  • 要重返未来,且命令行工具关闭了,可以使用git reflog查看命令历史,以便查找commit_id,回退到某个版本

工作区和暂存区

工作区(Working Directory)

就是你电脑里可以看到的目录,比如我的是My_git文件夹就是一个工作区

版本库(Repository)

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库 

Git的版本库里存了很多东西,其中最重要的就是stage(或者叫作index)的暂存区,还有Git为我们自动创建了第一个分支master,以及指向master的一个指针叫作HEAD

前面讲到过,把文件往Git版本库里添加的时候,需要两步;

第一步用git add命令把文件添加进去,实际上就是把文件修改添加到暂存区

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支

因为我们创建git仓库时,git自动为我们创建了唯一一个master分支,所以,git commit就是往master分支上提交更改。

 简单理解:需要提交的文件修改通通放到暂存区,然后一次性提交暂存区的所有修改

实践了,新建一个LICENSE.txt文件,但是没有提交,使用git status查看状态,它显示的是untracked file未追踪文件

使用git add添加后,其实就是下面的状态

 所以git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后执行git commit就可以一次性把暂存区的所有修改提交到分支

 一旦,提交之后,如果你没有对工作区做任何修改,那么工作区就是”干净的“:

 

这张图好像有点错误,暂存区的内容其实应该还在,不是没有了,只是和HEAD版本无差别了,无差别则不需要提交,所以nothing to commit并不是说暂存区没有内容了

小结

 工作区>>>>>>>>>>>>>暂存区>>>>>>>>>>>>>>>>仓库

  • git add 命令用于将文件从工作区添加到暂存区。
  • git commit 命令用于将暂存区中的文件提交到仓库。
  • git diff 命令用于查看工作区和暂存区之间的差异。
  • git diff --cached 命令用于查看暂存区和仓库之间的差异。
  • git diff HEAD 命令用于查看工作区和仓库之间的差异。
  • git add的反向命令git checkout 命令用于撤销工作区中的修改,即将暂存区中的最新版本转移到工作区。
  • git commit的反向命令git reset HEAD 命令用于将仓库中的最新版本转移到暂存区。就是把暂存区的修改取消

管理修改

Git跟踪并管理的是修改,而非文件

什么是修改,比如你新增了一行,这就是一个修改,删除一行,这也是一个修改,更改了某些字符,这也是一个修改,删了一些又增加了一些,也是一个修改,甚至创建一个新文件也算一个修改。

这里你可以做一个实验,修改一个文件,然后添加到暂存区,这时候如下:

 如果你再修改之后,不先添加到暂存区,直接提交,这里第二次的修改是没有添加到仓库中的。

就是这样一个流程:第一次修改->git add-> 第二次修改->git commit

最后结果就是第二次的修改没有更新到仓库中,第二次的修改没有放到暂存区中,所以git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。

使用git diff HEAD -- readme.txt可以查看版本库和工作区的区别:

结果就是第二次修改确实没有被提交。

小结

  • Git跟踪并修改的不是文件,而是修改
  • 在commit之前,务必保证add所有修改的文件,可以修改一次就add和commit一次,也可以先修改全部后add再commit,或者修改一次add一次,最后统一使用commit提交所有修改。
  • 确保在commit之前,add所有文件。
  • git diff HEAD -- readme.txt查看工作区和版本库的区别,--用来分隔选项和参数,这里只要文件名和选项不会相同,其实可以没有--,也可以用./readme.txt代替上面的-- readme.txt

撤销修改

在工作中很难遇到不犯错的情况,如果你的文件你添加了一些错误的修改,比如stupid boss写到了文档中,如果错误很小,你可以直接手动修改文件,如果此时你用git status查看一下

上面git已经说明了,你可以使用git restore <file>可以丢弃工作区的修改:

git restore readme.txt

其实也可以使用

git checkout -- readme.txt

但是git好像推荐restore指令。

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况(命令中的--很重要,缺少这个是一个分支命令)

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

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

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

上面的是修改还未提交到暂存区,如果你修改了文件并且添加到了暂存区,这时候git status一下可以发现

 git同样会提示我们git restore --stage <file>可以把暂存区的修改撤销掉(unstage),重新放回工作区

执行上面的撤销修改命令,输出如下,如果要把工作区的修改也撤销就是上面的内容,使用git restore <file>

 小结

  • 注意Git其实你每次git status它都会给出一些你可能用到的操作,要学会查看它的输出,上面就是通过使用git输出的信息里的命令进行撤销修改操作的
  • 当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,使用git restore <file>或者git checkout -- file
  • 当你不但改乱了工作区某个文件的内容,还添加到了暂存区,想丢弃修改,分为两步,第一步使用命令git restore --staged <file>或者git checkout -- file就回到了上面的场景,第二步就是重复上面的操作情况,撤销工作区的修改
  • 已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退内容,不过前提是没有推送到远程库
  • 从暂存区恢复工作区,
  • git resotre --worktree readme.txt
  • 从master恢复暂存区 
  • git restore --staged readme.txt
  • 从master同时恢复工作区和暂存区
  • git restore --source=HEAD --staged --worktree readme.txt

删除文件

在Git中,删除也是一个修改操作,我们可以先添加一个新文件test.txt到Git中并且提交:

 一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删除

rm test.txt

这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status 命令会立刻告诉你哪些文件被删除了:

 现在你有两个选择,一是确实要从版本库中删除该文件,那就用git rm删掉,并且git commit

这时文件从版本库中删除了

 小提示:git rm等价于先手动删除文件,再把修改添加到暂存区

注意:从来没有被添加到版本库就被删除的文件,是无法恢复的!

小结

  • 命令git rm用于删除一个文件,如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
  • Git status是个很常用的命令,可以提示你可能用到的命令

添加远程库

1、登录Github添加自己的仓库,创建完之后,它会提示我们可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后把本地仓库的内容推送到Github仓库

2、所以我们可以根据它的提示,如果你是在本地已经有一个仓库了,只需要运行下面的命令

git remote add origin git@github.com:OldLiao/learngit.git

 其中origin是你为远程库起的别名,因为它的名字其实是git@github.com:OldLiao/learngit.git,后面推送就可以不用打这么长一段,直接用origin代替。OldLiao是自己的GitHub账户名。

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

3、下一步就是把本地库的所有内容推送到远程库上:

git push -u origin master

把本地库的内容推送到远程,用git push命令,实际上就是把当前分支master推送到远程。

如果第一次远程库是空的,第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

推送成功以后,github远程库和本地库是一样的。

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

git push origin master

把本地master分支的最新修改推送至GitHub,现在就相当于拥有了真正的分布式版本库!以后也不用担心你的硬盘了!!!

删除远程库

如果你添加远程库,输入错了,或者就是想删除远程库,可以先用以下命令

git remote -v  //查看远程库信息
git remote rm  <name>  //删除远程库

 直接输入git remote rm origin就可以删除

小结

  • 要关联一个远程库,使用命令
  • git remote add origin git@server-name:path/repo-name.git
    
  • 关联一个远程库时必须给远程库起一个名字,origin是习惯默认名
  • 关联后第一次使用git push -u origin master第一次推送master分支所有内容
  • 此后每次提交,只需要用git push origin master推送最新修改
  • git remote show origin就是查看远程库是否有更新,如果有,我们可以使用git pull origin从服务器下载更新到本地仓库,本人经过实验确实如此
  • git push origin master和git pull origin是一对互相作用的命令,一个是推送本地修改到服务端,一个如果在github上做修改后,使用pull下载到本地仓库

从远程库克隆

简单的说就是从远程库克隆下载到本地仓库,使用命令

git clone git@github.com:OldLiao/gitskills.git

其中,git@github.com:OldLiao/gitskills.git是使用的ssh协议,GitHub它支持多种协议,还有https和cli等

小结

  •  要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆
  • git支持多种协议,包括https、但ssh协议速度最快

分支管理

创建与合并分支

在版本回退里,知道每次提交,git都把它们串成一条时间线,这条时间线就是一个分支,一开始git init创建了一个主分支叫作master,HEAD严格来说不是指向提交,而是指向master,master才是指向提交的。所以HEAD指向的就是当前分支

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

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

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

 

证明了我们说的HEAD指向的就是当前分支

可以看到Git创建一个分支很快,只需增加一个指针,改改HEAD的指向,工作区的文件没有任何变化。

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

 

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

 

所以git合并分支也简单,就是改改指针,工作区内容也不变。

合并完分支之后,甚至可以删除dev分支,删除dev分支就是把dev指针删掉,删掉后我们就剩下一条master分支:

 

命令

//创建分支并且切换到新分支
git checkout -b dev
git switch -c dev  //两条是一样的作用,switch更直观点

//查看当前分支
git branch  //该命令列出所有分支,带*号的是当前分支

//假如在dev分支上做了修改并且添加和提交,master查看文件还是没有修改的
//这就是上面说的,master指向的是之前的提交,所以没有变

 

合并分支

//切回master分支,git merge用于合并指定分支到当前分支
git merge dev //这时就合并了分支

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

当然,也不是每次合并都能Fast-forward,还有其他方式的合并。

合并完成后,就可以放心地删除dev分支了:

 删除分支

git branch -d dev//删除dev分支

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

switch

我们注意到切换分支使用git checkout <branch>,而前面讲过的撤销修改则是git checkout -- <file>,同一个命令,有两种作用,确实有点令人迷惑。

实际上,切换分支这个动作,用switch更科学。因此,最新版本的Git提供了新的git switch命令来切换分支:

创建并切换到新的dev分支,可以使用:

$ git switch -c dev

直接切换到已有的master分支,可以使用:

$ git switch master

使用新的git switch命令,比git checkout要更容易理解。

小结

Git鼓励大量使用分支:

  • 查看分支:git branch
  • 创建分支:git branch <name>
  • 切换分支:git checkout <name>或者git switch <name>
  • 创建+切换分支:git checkout -b <name>或者git switch -c <name>
  • 合并某分支到当前分支:git merge <name>
  • 删除分支:git branch -d <name>

 解决冲突

如果你准备一个新的分支,这时候,修改文件比如readme.txt,修改最后一行为任意内容修改,在新分支比如feature1提交 

 git add readme.txt
 git commit -m "and simple"

切换到master分支,git switch master

会提示如下

$ git switch master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。

master分支上把readme.txt文件的最后一行改为:

Creating a new branch is quick & simple.

提交:

$ git add readme.txt 
$ git commit -m "& simple"
[master 5dc6824] & simple
 1 file changed, 1 insertion(+), 1 deletion(-)

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

 

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

$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

 上面提示合并冲突了,git告诉我们,readme.txt文件存在冲突,使用git status命令查看,必须手动解决冲突后再提交。

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

 我们可以直接查看readme.txt的内容:然后修改冲突文件的内容,修改成和feature1分支一样的修改。再提交git add和git commit

结果如下:

用带参数的git log也可以看到分支的合并情况:

$ git log --graph --pretty=oneline --abbrev-commit

 最后删除feature1分支git branch -d feature1

小结

  • 当Git无法自动合并文件时,就必须先解决冲突,解决冲突后,再提交,合并完成
  • 解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
  • 用git log --graph命令可以看到分支合并图。

分支管理策略

通常,合并分支时,如果没有冲突,并且分支是单向一条线路继承下来的,git会使用 fast forword 模式,但是有些快速合并不能成功,但是又没有冲突时,就会触发分支管理策略,git会自动做一次新的提交。

当两个分支对工作区都进行了修改,但是修改的并不是同一个文件,而是两个不同的文件,也就是不会产生冲突。此时合并的时候,不能使用**“快速合并”**,就会弹框需要你输入一段合并说明。使用快捷键 ctrl+x 退出

合并时禁止快速合并模式

# 合并dev到master,禁止快速合并模式,同时添加说明
git merge --no-ff -m '添加描述' dev

小结

  • Git分支十分强大,在团队开发中应该充分应用。
  • 合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

bug分支

描述和说明

 使用场景:当在某个分支上工作,突然有个紧急的BUG需要修复,此时可以使用stash功能,将当前正在工作的现场存储起来,等bug修复之后,在返回继续工作。

对当前现场进行存储
git stash
切换到bug出现的分支上,比如bug出现在 master分支。如果bug就是在当前分支,可以操作此步骤

git checkout master
新添加一个bug临时分支

git checkout -b bug001
对代码进行修复。

切换回master分支

git checkout master
合并bug分支到主master上

git merge --no-ff -m '合并bug分支到master' bug001
删除bug001分支

git branch -d bug001
回到之前的工作现场所在的分支

git checkout dev

查看当前分支保存那些工作现场(之前封冻存储的工作现场)

git stash list

恢复存储的现场

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

$ git stash apply stash@{0}

 小结

  • 修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除。
  • 当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场;
  • 在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>命令,把bug提交的修改“复制”到当前分支,避免重复劳动。

参考

创建标签 - 廖雪峰的官方网站 (liaoxuefeng.com)

geeeeeeeeek/git-recipes: 🥡 Git recipes in Chinese by Zhongyi Tong. 高质量的Git中文教程. (github.com) 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值