git和github相关

387 阅读10分钟

定义

git:一个代码版本控制系统。
github:是网上代码仓库,你写的代码的各个版本都可以存着。

背景

版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。经历了从本地版本控制系统,集中化的版本控制系统,分布式版本控制系统三种。git便是分布式版本控制系统在git下客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来(clone)。

区别 (重点理解快照)

git和其他版本控制系统一个更重要的区别是,对管理的文件处理方式的不同。所有除了Git以外的版本控制系统都使用增量存储方式来保存不同版本即记录文件的每一次变化的内容,也就是记录具体发生了哪些差异和上一个版本相比产生哪些变化。Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git不再重新存储该文件,而是只保留一个链接指向之前存储的文件。git更像一个快照流。前者记录每个版本差别后者记录对当前全部文件的快照

git相关

.普通文件夹和git仓库的区别:区别在仓库文件夹中会有一个.git文件夹使它成为仓库的原因可用ls -al命令查看。通常会有两种方式建立
第一种为使用以下代码。
$ git init
该命令将创建一个名为 .git的子目录,这个子目录含有你初始化的Git仓库中所有的必须文件,这些文件是 Git 仓库的骨干。但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。
第二种为直接clone一个仓库,如果你想获得一份已经存在了的Git仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到gitclone命令。当你执行gitclone命令的时候,默认配置下远程Git仓库中的每一个文件的每一个版本都将被拉取下来。
git clone [url]在本地创建原名字目录or
git clone [url] [自定义本地仓库的名字]在本地创建新名字目录
git clone [url] . 不会创建新目录,在当前目录创建代码和.git。保证当前目录是空的
.初次运行 Git 前的配置:Git自带一个gitconfig的工具来帮助设置控制Git外观和行为的配置变量。这些变量存储在三个不同的位置:
1./etc/gtconfig文件:包含系统上每一个用户及他们仓库的通用配置。如果使用带有 --system选项的 git config 时,它会从此文件读写配置变量。
2.~/.gitconfig 或 ~/.config/git/config文件:只针对当前用户。可以传递--global选项让Git读写此文件。
3.当前使用仓库的 Git 目录中的config文件(就是.git/config):针对该仓库。每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖/etc/gitconfig中的配置变量。 可以使用 git config --list 命令来列出所有 Git 当时能找到的配置
. 文件状态演变: Git 项目的三个工作区域的概念:Git仓库目录、工作目录以及暂存区域。Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。这是Git中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。工作目录是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在Git仓库目录中。有时候也被称作“索引”,不过一般说法还是叫暂存区域。
基本的 Git 工作流程如下:

1.在工作目录中修改文件。
2.暂存文件,将文件的快照放入暂存区域。
3.提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。

如果 Git 目录中保存着特定版本的文件,就属于已提交状态。
如果作了修改并已放入暂存区域,就属于已暂存状态。
如果自上次取出(已追踪)后,作了修改但还没有放到暂存区域,即提交后被修改状态,就是已修改状态。

工作目录下的每一个文件都不外乎这两种状态:已跟踪或未跟踪。已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录(指已提交过的),在工作一段时间后,它们的状态可能处于未修改,已修改或已放入暂存区。 工作目录中除已跟踪文件以外的所有其它文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有放入暂存区。 要查看哪些文件处于什么状态,可以用git status命令。初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态。 git status 命令的输出十分详细,但其用语有些繁琐。 如果你使用 git status -s 命令或 git status --short 命令,你将得到一种更为紧凑的格式输出。

跟踪新文件or暂存已修改文件

使用命令 git add 开始跟踪一个文件。相当于做了该文件被跟踪且新增文件这个变更加入了暂存区。 这是个多功能命令可以用它开始跟踪新文件(做了两件事情),或者把已跟踪的文件放到暂存区。

提交更新

运行提交命令 git commit,Git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交。可以在 commit 命令后添加 -m 选项,给提交注释。-am=-a+-m。参数-v可以详细的提交

移除文件

git rm readme.md这条命令做了两件事把read.md从工作目录(本地)删除而且把删除这个变更加入暂存区。等同于rm readme.md,gitaddreadme.md.等待提交。我们想把文件从Git仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 使用git rm --cached README。然后提交。要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域(快照)移除),然后提交。
总结:git rm readme.md : 把readme.md文件移除的这个变动暂存,并且本地也删除 readme.md文件 。
git rm --cached readme.md:把readme.md文件移除的这个变动暂存,但本地保留readme.md文件(该文件变成未追踪状态)。
git rm -f readme.md:对于被提交后做了修改(处于已修改状态)的文件,想把文件移除的变动暂存必须加 -f参数

忽略文件

一般我们总会有些文件无需纳入Git的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者译过程中创建的临时文件等。在这种情况下,我可以创建一个名为.git ignore 的文件,列出要忽略的文件模式。
#忽略.a为后缀的文件
*.a
# 尽管上面忽略了.a为后缀的文件,但不忽略lib.a
!lib.a
# 只忽略当前目录下的TODO文件,但不忽略子目录下的TODO文件
/TODO
# 忽略build/目录下的所有文件
build/
# 忽略doc/notes.txt,但不忽略 doc/server/a.txt
doc/*.txt
# 忽略doc/目录下的所有的 .pdf文件
doc/**/*.pdf

撤消操作

  1. $ git commit --amend 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。这个命令会将暂存区中的文件提交,需要再次更新暂存区。最终你只会有一个提交——第二次提交将代替第一次提交的结果。(相比提交两次节省空间)。
  2. git reset 你已经修改了两个文件并且想要将它们作为两次独立的修改提交,但是却意外地输入了 git add * 暂存了它们两个。 如何只取消暂存两个中的一个呢?该命令会撤销暂存区的快照但不会使工作目录修改撤销即保留对文件的修改。
  3. git checkout你对那个文件做的任何修改都会消失——你只是拷贝了另一个文件来覆盖它。除非你确实清楚不想要那个文件了,否则不要使用这个命令。不保留对文件的修改而且撤销暂存区域的。

远程仓库

  1. git remote -v如果想查看你已经配置的远程仓库服务器
  2. git remote add <shortname> <url>添加一个新的远程Git仓库,同时指定一个你可以轻松引用的简写。
  3. git remote set-url <shortname> <url>修改shortname代表的url
  4. git remote rename <shortname> <shortname> 重命名
    远程仓库地址默认的名字叫 origin
  5. git push <远程主机名> <本地分支名>:<远程分支名>git push origin master 推送项目一个分支 通常是默认分支一致,则可以使用 -u 参数指定一个默认主机,这样后面就可以不加任何参数使用git push, 不带任何参数的git push,默认只推送当前分支,这叫做simple方式 通常有些仓库对你只读,有些则可以读写。对应git remote -v中的fetch和push(通常本地远程分支同名)。
  6. 没法单独下载某一个分支很复杂
  7. git pull <远程主机名> <远程分支名>:<本地分支名>即将远程主机的某个分支的更新取回,并与本地指定的分支合并如果远程分支是与当前分支合并,则冒号后面的部分可以省略。有冲突解决冲突

给Git命令起个简短的名字

1.git config --global alias.ci commit可以在 ~/.gitconfig 里查看和设置 alias
2.修改 ~/.bashrc,在文件末尾加上alias gci="git commit"保存后,执行source ~/.bash
前者必须命令前加git,后者皆可。

分支

在讲述分支前先对git原理进行理解在之前提到过git add git commit会发生什么:

  1. 在工作目录中修改文件。

  2. 暂存文件,将文件的快照放入暂存区域。

  3. 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。

  4. 首先创建两个文件

$ git init
$ echo '111' > a.txt
$ echo '222' > b.txt
$ git add *.txt  
  1. Git会将整个数据库储存在.git/目录下,如果你此时去查看.git/objects目录,你会发现仓库里面多了两个object。可以发现这个object是一个blob类型的节点,他的内容是哈希值代表着111,也就是说这个object储存着a.txt文件的内容。这里我们遇到第一种Gitobject,blob类型,它只储存的是一个文件的内容,不包括文件名等其他信息。然后将这些信息经过SHA1哈希算法得到对应的哈希值,作为这个object在Git仓库中的唯一身份证。我们此时的Git仓库是这样子的:


3. 当我们commit完成之后,Git仓库里面多出来两个object。这里我们遇到了第二种Gitobject类型——tree,它将当前的目录结构打了一个快照。从它储存的内容来看可以发现它储存了一个目录结构(类似于文件夹),以及每一个文件(或者子文件夹)的权限、类型、对应的身份证(SHA1值)、以及文件名。此时的Git仓库是这样的(树对象记录了结构和blob索引):

$ git cat-file -t 4caaa1
tree
$ git cat-file -p 4caaa1
100644 blob 58c9bdf9d017fcd178dc8c0...     a.txt
100644 blob c200906efd24ec5e783bee7...    b.txt  


4. 接着我们发现了第三种Gitobject类型——commit,它储存的是一个提交的信息,包括对应目录结构的快照tree的哈希值,上一个提交的哈希值(这里由于是第一个提交,所以没有父节点。在一个merge提交中还会出现多个父节点),提交的作者以及提交的具体时间,最后是该提交的信息(提交对象记录了树对象的索引和上一个提交对象的索引)哈希值即是索引。

$ git cat-file -t 0c96bf
commit
$ git cat-file -p 0c96bf
tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209
author lzane 李泽帆  1573302343 +0800
committer lzane 李泽帆  1573302343 +0800
[+] init  

Git 仓库中有五个对象:三个blob对象(保存着文件快照)、一个树对象(记录着目录结构blob对象的结构和各blob对象索引)以及一个提交对象(包含着指向前述树对象的指针和所有提交信息以及树对象的索引)。

Git的分支,其实本质上仅仅是指向提交对象的可变指针。做些修改后再次提交,那么这次产生的提交对象会包含一个指向上次提交对象(父对象)的指针。在Git仓库里面,HEAD、分支、普通的Tag可以简单的理解成是一个指针,指向对应commit的SHA1值。

理解树对象就是快照,git add会新建一个tree相当于对工作目录进行一次快照,commit后旧的tree不会消失这与每次commit,Git储存的是全新的文件快照相对应。

  1. 在工作目录中修改文件。
  2. 暂存文件,将文件的快照放入暂存区域。(更新tree的索引)
  3. 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。(建立提交对象包含对tree的索引)

分支创建

它只是为你创建了一个可以移动的新的指针。 比如,创建一个 testing 分支, 你需要使用 git branch 命令:$ git branch testing

`
,Git 又是怎么知道当前在哪一个分支上呢? 也很简单,它有一个名为 HEAD 的特殊指针。 git branch 命令仅仅 创建 一个新分支,并不会自动切换到新分支中去。

分支切换

要切换到一个已存在的分支,你需要使用 $ git checkout testing 命令。 我们现在切换到新创建的 testing 分支去若当前目录中有未提交的文件,只要不与另一个分支冲突就不需理会。若冲突了提交即可或者使用git stash

查看所有分支

git branch -a

删除分支

git branch -d bugfix

创建并切换

git checkout -b bugfix

分支的合并和冲突

$ git checkout master
$ git merge hotfix    将另一个分支合并到当前分支


合并master和hotfix 合并完成后记得删除多余分支。

遇到冲突时的分支合并

有时候合并操作不会如此顺利。 如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。 此时 Git 做了合并,但是没有自动地创建一个新的合并提交。 Git 会暂停下来,等待你去解决合并产生的冲突。 你可以在合并冲突后的任意时刻使用 git status 命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件。任何因包含合并冲突而有待解决的文件,都会以未合并状态标识出来。 Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。 出现冲突的文件会包含一些特殊区段,看起来像下面这个样子:

<<<<<<< HEAD:index.html  
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
 please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

为了解决冲突,你必须选择使用由 =======分割的两部分中的一个,或者你也可以自行合并这些内容。

切换版本

git reset --hard 版本哈希前6个哈希可用git log OR git reflog查看。原因:由提交对象可以复原整个文件快照。区别:log可查看之前版本。reflog可查看版本变迁的记录
git reset --hard 版本哈希前6个会把未暂存的全部删掉

Github原理

github上有一个账户,电脑上有一个仓库,github怎么知道两个都是你的,即如果一台电脑向github账户推送代码账户怎么验证电脑身份,通常情况会输入你要上传账户的账号密码但是github不采用这种方法,采用公钥私钥的方式来识别。公钥保存在github上,私钥保存在电脑上,每次push代码时用私钥加密后push,然后github会用公钥解密,私钥公钥可互相解密ssh方式。自己的账户用ssh,别人的用HTTPS。
例:若一个github里面有多个公钥,证明有多台电脑可以上传代码。

  • ssh-keygen -t rsa -b 4096 -C 你的邮箱得到公钥私钥内容
  • cat ~/.ssh/id_rsa.pub得到公钥内容,往github里面输入公钥内容
  • ssh -T git@github.com 从github上接受公钥验证从而建立一对一联系

默认情况下,用户的 SSH 密钥存储在其 ~/.ssh 目录下。我们需要寻找一对以 id_dsa 或 id_rsa 命名的文件,其中一个带有 .pub 扩展名。 .pub 文件是你的公钥,另一个则是私钥。

markdown

Markdown是一门标记语言一般后缀为.md或.markdown,详情查询具体网站的文档,各有不同

git-scm.com/book/zh/v2
git-scm.com/docs
zhuanlan.zhihu.com/p/96631135