全面详细、通俗易懂的Git和GitHub

前言

本文内容是《ProGit2》一书的精简笔记。

基础操作

配置

安装完Git应该做的第一件事就是配置用户名与邮箱,因为每一次提交都会使用这些信息:

git config --global user.name <username>
git config --global user.email <useremail>

通过以下命令可以查看所有的Git配置:

git config --list 

获取仓库

接下来就要获取Git仓库,通常有以下两种方式:

  • 将尚未进行版本控制的本地目录转换为 Git 仓库。
  • 从其它服务器 克隆 一个已存在的 Git 仓库。

如果有一个尚未进行版本控制的项目目录,想要用 Git 来控制它,那么首先需要进入该项目目录,然后使用以下命令:

git init

该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件。我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。如果想要克隆一个已存在的仓库需要使用以下命令:

git clone <url>

项目的区域

得到Git仓库后便得到了一个Git项目,一个Git项目有三个重要的区域:

  • 工作区:存放项目的某个版本独立提取出来的内容。
  • 暂存区:暂存区是一个文件,保存了下次将提交的文件列表信息,这个文件存放在本地仓库中。
  • Git仓库: 用于保存项目的元数据和对象数据库。

在这里插入图片描述

文件的状态

项目中的文件也有不同的状态:

  • 未跟踪:未被Git管理的文件,也就是未被纳入版本控制的文件。
  • 已跟踪:已被纳入版本控制的文件。
  • 未修改:没有被修改的已跟踪文件。
  • 已修改:被修改的已跟踪文件。
  • 已暂存:被包含在下次提交快照中的已跟踪文件。

在工作区的文件可能是前四种状态之一,在暂存区的文件处于已暂存状态,它们的关系如下图所示:
在这里插入图片描述

add命令可以将一个未跟踪文件直接变为已暂存状态:

git add <files>|<dirs> #如果参数为目录,那么git会递归添加目录中的文件

commit命令可以将已暂存文件提交到本地库:

git commit <options> #此时会启动编辑器来输入提交说明
	- m <declare> #直接跟提交说明
	- a  #跳过使用暂存区,自动把所有已经跟踪过的文件暂存起来一并提交
	-- amend #该选项会将暂存区中的文件提交。 如果自上次提交以来还未对已跟踪文件做任何修改,那么快照会保持不变,最终第二次提交将代替第一次提交的结果。

log命令可以查看提交历史:

git log 

rm命令可以将文件从项目中删除(连带从工作区删除),下一次提交时,该文件就不再纳入版本管理了。 如果要删除之前修改过或已经放到暂存区的文件,则必须使用选项-f,如果只想从Git中删除,则需要使用-cached选项:

git rm <options> <files>
	- f 
	- cached 

mv指令可以移动文件,不过Git不显式跟踪文件的移动,而是将这种行为视作一次改名行为:

git mv <src> <des>

可以使用以下命令查看文件的状态:

git status

该命令会将某些状态下的文件在提示语下列举:

提示语文件状态
Untracked files未跟踪
Changes not staged for commit已修改
Changes to be committed已暂存

值得注意的是同一个文件可能同时处于已修改和已暂存状态,这种情况是因为这个文件暂存后又被修改了且没有重新暂存。

.gitignore

总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。在这种情况下,可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。

匹配规则说明
匹配某个字符
*匹配多个字符
**任意中间目录
[char]包含单个字符的匹配列表
[char-char]包含字符范围的匹配列表
!不忽略匹配到的文件或目录
/以/开头放置递归,以/结尾指定目录

远程仓库

远程仓库是指托管在因特网或其它网络中的项目版本库。 以下是远程仓库的简单操作:

#查看远程库
git remote [options] 
	- v #显示远程库地址
#添加远程库
git remote add <shortName> <url>
#移除远程库
git remote rm <remote>
#重命名远程仓库
git remote rename <oldName> <newName>

在这里插入图片描述
fetch命令可以访问远程仓库,从中拉取本地库中没有的数据到本地库,但该命令不会自动合并或修改当前的工作。

git fetch <remote>

标签

Git 可以给历史中的某一个提交打上标签,tag命令可以查看标签:

git tag

在Git中有两种标签:

  • 轻量标签:是一个特定提交的引用。
  • 附注标签:附注标签是存储在 Git仓库中的一个完整对象,其中包含打标签者的名字、电子邮件地址、日期时间和标签信息。
git tag [options] <tagName> <checksum> #为当前提交创建一个轻量标签
	- a #为当前提交创建一个附注标签
	- m <tagMessage> 
	- d #删除本地库标签

默认情况下push 命令并不会传送标签到远程库。 在创建完标签后必须显式地推送:

git push [options] <remote> <tagName>
	-- tags #推送所有不在远程仓库的标签
	--delete #删除远程库的标签

在 Git 中并不能真的检出一个标签,因为它们并不能像分支一样来回移动。 如果想要工作目录与仓库中特定的标签版本完全一样,可以使用 以下命令在特定的标签上创建一个新分支:

git checkout -b <branchName> <tagName>

核心操作

Git是一个文件系统,它将文件存储为一系列不同时刻的快照,进行暂存操作会为每一个文件计算校验和,然后会把当前版本的文件快照保存到Git 仓库中,最终将校验和加入到暂存区域等待提交:
在这里插入图片描述
进行提交操作时,Git 会每个文件的校验和保存为Git 仓库中的树对象:
在这里插入图片描述
随后,Git 便会创建一个提交对象,该对象包含了作者的姓名和邮箱、提交时输入的信息和指向树对象的指针:
在这里插入图片描述
还可能包含指向它的父对象的指针,首次提交产生的提交对象没有父对象,普通提交操作产生的提交对象有一个父对象, 而由多个分支合并产生的提交对象有多个父对象:
在这里插入图片描述
如此一来,Git 就可以在需要的时候重现某次保存的快照。

分支

Git 的分支,本质上是指向提交对象的可变指针, Git 的默认分支名字是 masterinit命令会默认创建master 分支,并且它会在每次提交时自动向前移动。
在这里插入图片描述
也可以通过以下命令管理分支:

git branch <branchName> #创建分支
	- d #删除分支
	- D #删除分支并且丢掉工作
	- vv #显示详细信息

push命令可以将本地的localBranch分支来更新远程库的remotelBranch分支。如果在推送前远程分支被修改,那么必须先拉取处理修改,否则推送将失败。

git push <remoteName> <localBranchName>:<remotelBranchName>

HEAD

HEAD是一个指针,指向当前的分支。
在这里插入图片描述
切换分支就是改变HEAD的指向,切换分支时工作区会恢复到切换的分支最后一次提交的样子,在此之前,要留意工作区和暂存区里那些还没有被提交的修改, 它可能会和即将检出的分支产生冲突从而阻止 Git 切换到该分支。:

git checkout [options] <branchName>
	- b <newbranchname> #创建一个新分支并切换过去

merge命令用于合并分支,合并分支会遇见三种情况:

  • 当合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进:
    在这里插入图片描述
    在这里插入图片描述

  • master分支所在提交并不是testBranch分支所在提交的直接祖先时,Git 会使用两个分支的末端所指的快照(C4 和 C5)以及这两个分支的公共祖先(C2),做一个简单的三方合并。Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。
    在这里插入图片描述
    在这里插入图片描述

  • 如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。此时Git 会暂停下来,等待你去解决合并产生的冲突。解决完成后将修改后的文件提交就完成了合并。

  • 如果冲突发生不想修改还可以通过git merge --abort命令放弃合并。

如果想撤销一次成功的合并有两种方法,第一种是下文重置中的方法,第二中方法是使用下面的命令:

git revert <key>

该命令会新建一个提交对象C6,C6的内容和C3的内容完全一致,这就像没合并一样:

  • 合并前:
    在这里插入图片描述
  • 合并后:
    在这里插入图片描述
  • 撤销后:
    在这里插入图片描述

如果在撤销后我们做了一些工作后又想合并这两个分支,那么Git只会引入被撤销的合并之后的修改,此时需要使用revert命令撤销撤销合并的提交,也就是撤销C6,这样还会产生一个撤销对象C7,在C7的基础上再次合并就解决了这个问题。

重置

假设我们进入到一个新目录,其中有一个文件。 我们称其为该文件的 v1 版本,现在运行 git init,这会创建一个 Git 仓库,其中的 HEAD 引用指向未创建的 master 分支:
在这里插入图片描述
现在我们想要提交这个文件,所以用add命令将该文件添加到暂存区:
在这里插入图片描述
接着使用commit命令提交:
在这里插入图片描述

然后在工作区中修改文件。 我们称其为该文件的 v2 版本:
在这里插入图片描述
接着我们运行 add 命令来将它暂存:
在这里插入图片描述
最后,再使用 commit 命令完成提交:
在这里插入图片描述
当检出一个分支时,它会修改 HEAD 指向新的分支引用,将缓冲区填充为该次提交的快照,然后将缓冲区的内容复制到工作区中。再次修改文件并第三次提交它:
在这里插入图片描述
此时如果想回到v2版本,可以使用以下命令,该过程需要经过三个步骤:

git reset [options] <key>
	-- soft #在第一步停止
	-- mixed #在第二步停止,默认行为
	-- hard #进行第三步
  • 第一步:移动HEAD及其指向的分支:
    在这里插入图片描述
  • 第二步:更新缓冲区:
    在这里插入图片描述
  • 第三步:更新工作区:
    在这里插入图片描述

如果给reset命令提供一个作用路径,那么它将会跳过第一步,并且将它的作用范围限定为指定版本的指定文件或文件集合。

git reset [options] <key> <file>
	-- hard #进行第三步

如果要撤销对一个已修改文件的修改,可以使用以下指令,该指令会用最近提交的版本覆盖掉它:

git restore <file>

远程分支

远程分支是远程库分支状态的引用。它们是无法移动的本地引用。一旦你进行了网络通信, Git 就会为你移动它们以精确反映远程仓库的状态。它们以<remote>/<branch> 的形式命名。 clone 命令会自动将远程库命名为 origin,拉取它的所有数据, 创建一个指向它的 master 分支的origin/master远程分支, 同时也会创建一个与origin/master远程分支的指向同一个地方的本地 master 分支。
在这里插入图片描述

跟踪分支

从远程跟踪分支检出的本地分支称为跟踪分支,当克隆一个仓库时,它通常会自动地创建一个跟踪 origin/master 远程分支的 master 跟踪分支,可以通过以下方式创建跟踪分支:

git checkout [options] <remote/branch>
	--track #创建同名跟踪分支
	- b <branch> #创建自定义名称跟踪分支
	- u  #修改当前跟踪分支的远程分支

以下命令可以删除远程分支。

git push <remote> --delete <branch>

pull命令会查找当前分支所跟踪的远程库分支, 从远程库上抓取数据然后尝试合并那个远程分支:

git pull

GitHub

开源项目

如果想要参与某个开源项目,但是并没有推送权限,这时可以对这个项目进行Fork
在这里插入图片描述
Fork一个项目时,GitHub 会在你的空间中创建一个完全属于你的项目副本,且你对其具有推送权限。通过这种方式,项目的管理者不再需要忙着把用户添加到贡献者列表并给予他们推送权限。 人们可以派生这个项目,将修改推送到派生出的项目副本中,并通过创建拉取请求(Pull Request,简称 PR)来让他们的改动进入源版本库。创建了拉取请求后,就会开启一个可供审查代码的板块,项目的拥有者和贡献者可以在此讨论相关修改,直到项目拥有者对其感到满意,并且认为这些修改可以被合并到版本库。流程通常如下:

  • 派生一个项目
  • master 分支创建一个新分支
  • 提交一些修改来改进项目
  • 将这个分支推送到 GitHub 上
  • 创建一个拉取请求
  • 讨论,根据实际情况继续修改
  • 项目的拥有者合并或关闭你的拉取请求
  • 将更新后的 master 分支同步到你的派生中

当你派生一个 GitHub 仓库之后,派生的仓库会独立于原仓库而独立。当原仓库有新的提交时,GitHub 会通知你,但是派生仓库不会自动更新,必须手动进行:

git checkout master #如果在另一个分支上,就切换到 master
git pull https://github.com/progit/progit2.git #从原仓库拉取更新合并到master
git push origin master # 将 master 分支推送到 origin

管理项目

可以创建一个版本库来分享自己的项目,通过简单的设置后就在 GitHub 上拥有了一个以 <user>/<project_name> 命名的新仓库了。
在这里插入图片描述
如果想要添加合作者并给他们推送的权限,可以通过以下方式添加他们:
在这里插入图片描述
可以通过以下方式切换默认分支,其他人将默认会在这个分支上开启合并请求或进行浏览,他人进行克隆时该分支也将被默认检出。
在这里插入图片描述

在我们的代码库收到的PR可能来自仓库副本的一个通知,也可能来自同一仓库的另一个分支,如果想把它合并进来,可以把代码拉取下来在本地进行合并,或使用上文提到过的 git pull <url> <branch> 语法,也可以使用 GitHub 网站上的 Merge 按钮在线合并。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亻乍屯页女子白勺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值