关于版本控制:Git学习笔记

4次阅读

共计 9522 个字符,预计需要花费 24 分钟才能阅读完成。

Git 装置

linux

 $ sudo yum install git

mac: http://git-scm.com/download/mac

windows: http://git-scm.com/download/win

git 官网文档: https://git-scm.com/book/zh/v2

Git 装置完之后,须要做最初一步配置,如果你没有做这项配置,是没有 git 公钥和私钥的,而 上传代码到近程仓库 的时候须要秘钥进行验证是否自己上传的,想要创立能够应用上面的办法:

关上 git bash,别离执行以下两句命令
git config --global user.name“用户名”git config --global user.email“邮箱”

config 的三个作用域

--local 只对某个仓库无效
--global 对以后用户所有仓库无效
--system 对系统所有登录的用户无效
--list

SSH 配置

  1. 关上 git bash。
  2. 应用 cd ~/.ssh 能够查看是否已配置 SSH。
  3. 执行生成公钥和私钥的命令 ssh-keygen -t rsa 并按回车 3 下(为什么按三下,是因为有提醒你是否须要设置明码,如果设置了每次应用 Git 都会用到明码,个别都是间接不写为空,间接回车就好了)。会在一个文件夹外面生成一个私钥 id_rsa 和一个公钥 id_rsa.pub。(可执行start ~ 命令,生成的公私钥在 .ssh 的文件夹外面)。
  4. .ssh 如果不做非凡解决的话,个别是在 C:\Users\Administrator 目录下。如果看不到.ssh 文件,能够应用 ls -ah 指令查看暗藏文件夹即可,这是寄存秘钥的文件,关上这个文件会看到 id_rsa 和 id_rsa.pub。id_rsa 是私钥文件,id_rsa.pub 是公钥文件。
  5. 执行查看公钥的命令cat ~/.ssh/id_rsa.pub

建 Git 仓库

两种场景:

1. 把已有的我的项目代码纳入 Git 治理

cd 我的项目代码所在的文件夹
git init

2. 建设新的我的项目间接用 Git 治理

cd 某个文件夹
git init your_project #会在以后门路下创立和我的项目名雷同的文件夹
cd your_project
mkdir 创立目录
echo "" > 文件名 创立文件
clear 清屏

在仓库中增加文件

1. 将文件拷贝到工作目录

cp ... .

2. 测试文件符合要求后增加到暂存目录

git add files
git add -u 所有文件

3. 查看文件是否被 git 治理

git status

4. 提交暂存区的文件

git commit -m'更改理由' -am'..' 从工作区间接提交

git add 更新将要提交的内容
git restore 放弃工作目录中的更改
git rm 移除

Git 和其余版本控制系统如 SVN 的一个不同之处就是有暂存区的概念。

工作区(Working Directory)

就是你在电脑里能看到的目录,比方我的 learngit 文件夹就是一个工作区

版本库(Repository)

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

Git 的版本库里存了很多货色,其中最重要的就是称为 stage(或者叫 index)的暂存区,还有 Git 为咱们主动创立的第一个分支 master,以及指向master 的一个指针叫HEAD

git add把文件增加进去,实际上就是把文件批改增加到暂存区;

git commit提交更改,实际上就是把暂存区的所有内容提交到以后分支。

给文件重名名

git mv old new
操作完后 commit 提交

查看版本历史, 提交日志

git log -n5 --oneline 最近 5 条 扼要 
git log --all --graph 所有分支 图像化关系

版本历史图形化工具

gitk
查看分支
git branch -v
创立分支
git checkout -b 分支名 commitid
切换分支
git checkout 分支名

查看某个命令的帮忙文档

git help --web 命令  --web 在网页

.git 目录

HEAD 文件: 指向了当初援用的分支

cat HEAD
ref: refs/heads/master

config 文件: 记录了用户的信息

refs/: 援用目录, 蕴含了 heads 和 tags 目录

​ tags: 标签 里程碑, 我的项目开发到肯定水平, 给 commit 打一个标签如[v1.0]

​ 标签文件是 tag 类型 自身有一个 40 位的哈希值 , 内容蕴含了一个 commit 的类型的 object

​ heads: 分支, 如前后端建设独立的分支, 互不影响, 须要集成时可合并到一个公共的分支

​ 查看文件对象类型

cat 分支文件
git cat-file -t 哈希值
-p 看内容
如果哈希值足以保障唯一性能够应用短的一部分

​ master 文件为 commit 类型

​ git branch -av 查看分支能够看到 master 分支援用指针就是 heads 目录中 master 文件的哈希值

objects/: 所有文件对象

git 在每次 commit 的时候都会生成一个 tree 对象、一个 parent 对象(如果不是第一次提交的话)、和一个 commit 对象,这个最顶层的 tree 就是对应整个工作目录,tree 上面还有 blob、tree 对象,都是一串 hash 值指向对应的内容,当某个文件产生变动的时候会从新保留一次快照(hash),如果文件没有产生变动,保留的快照仍然是上次的。

涣散对象 (loose object) 会被打包到 pack/ 目录

查看文件对象类型 为:tree

git cat-file -t 文件名 + 哈希值

查看内容 蕴含一个 blob 文件, 就是提交的内容

git cat-file -p 文件名 + 哈希值

git 对象彼此的关系

每一次提交都会创立一个 commit 对象, 一个 commit 对象对应蕴含一个 tree 对象,tree 代表了以后工夫点仓库目录构造的快照,blob 指具体的文件, 在 git 中如果两个文件内容雷同就看作一个文件, 不管文件名

git 拆散头指针

如果不小心通过 git checkout 命令切换到某个 commit 中(即 HEAD 指向某个 commit),git 会提醒咱们正处于拆散头指针的状态下(工作在没有分支的状况下),如果咱们做了大量的批改,然而某天咱们忽然又切换到另一个 commit 时,咱们的批改就有可能被 git 当做垃圾革除掉,因而这个动作非常危险。

拆散头指针的用途:进行尝试性的变更时

试着批改某些文件时,如果感觉批改的成果不称心,能够间接切换到别的分支,抛弃以后批改

如果咱们切换进来时,感觉以后的批改非常重要,就依照 git 的提醒创立一个新分支

如果某个变更(提交)是十分重要的,那么肯定要跟某个分支绑定在一起

创立新分支:git checkout -b  新分支名称  基于某个分支或者 commit

eg:git checkout -b newBranch master

比拟某两个 commit 的区别

git diff 第一个 commit 第二个 commit

eg:git diff HEAD HEAD^1  (以后的 HEAD 指向的 commit 和他的父级进行比对)

HEAD^ ==HEAD~ == HEAD^1 == HEAD~1

HEAD^^ == HEAD^1^1 == HEAD^2

删除不须要的分支

git branch -D 分支名

批改 commit 的 message

对最近一次 commit 的 message 做变更

git commit --amend 

更改之前的 message

git rebase -i 需更改 commit 的父级 id 
执行后进入编辑, 把须要批改的一次 message 后面的 'pick' 改为 'r' 或 'reword', 保留退出, 会跳转到批改 message

合并多个间断的 commit

git rebase -i 父级 commitid
执行后进入编辑, 仅保留要合并到的 commit 的 'pick', 把须要须要合并的几个 'pick' 改为 's' 或 'squash', 退出保留, 批改阐明

合并多个距离的 commit

首先 git log --graph 查看 commit 历史

变基 git rebase -i 父 commitid 进入 vi

将父 commitid 拷贝进来并扭转程序, 放在要合并的 commit 下面

要合并的 commit 的 ’pick’ 改为 ’s’

pick acf475ed #父 commit
s 7ac3c1cb8b92 #要合并的 commit
... 其余

保留退出后报错:interactive rebase in progress; onto 7ac3c1c

而后执行 git rebase --continue 持续变基, 进入 vi

怎加一个 message, 保留退出即可

其余参考:https://segmentfault.com/a/11…

git 解决合并抵触

什么是合并抵触

在 Git 中,“合并(merging)”是在模式上整合别的分支到你以后的工作分支的操作。你须要失去在另外一个上下文背景下的改变(这就也就是咱们所提到过的,一个无效的分支应该是建设在一个上下文工作背景上的),并且合并它们到你的以后的工作文件中来。

作为你的版本管理系统,Git 所带来的最平凡的改善就是它让合并操作变得十分轻松简略。在大多数状况下,Git 会本人弄清楚该如何整合这些新来的变动。

当然,也存在极少数的状况,你必须本人手动地通知 Git 该怎么做。最为常见的就是大家都改变了同一个文件。即使在这种状况下,Git 还是有可能主动地发现并解决掉这些抵触。然而,如果两个人同时更改了同一个文件的同一行代码,或者一个人改变了那些被另一个人删除了的代码,Git 就不能简略地确定到底谁的改变才是正确的。这时 Git 会把这些中央标记为一个抵触,你必须首先解决掉这些抵触,而后再持续你的工作。
如何解决合并抵触

当面对一个合并抵触时,咱们首先要搞明确产生了什么。例如是不是你和你的共事都同时编辑了同一个文件的同一行代码呢?是不是他删除了一个你正在编辑的文件呢?是不是你们同时增加了一个雷同文件名的文件呢?
当你应用“git status”时,Git 会通知你存在一个“未合并的门路(unmerged paths)”,这只是用另外一个形式通知你,存在一个或多个抵触:

$ git status
# On branch contact-form
# You have unmerged paths.
#   (fix conflicts and run "git commit")
#
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#
#       both modified:   contact.html
#
no changes added to commit (use "git add" and/or "git commit -a")1234567891011

就让咱们来深刻地探讨一下,如何去解决这些最常见的抵触。
当两个改变产生在同一个文件的同一些行上,咱们就要看看发生冲突的文件的内容了。Git 会十分敌对地把文件中那些有问题的区域在“<<<<<<< HEAD”和“>>>>>>> [other/branch/name]”之间标记进去。

第一个标记后的内容源于以后分支。在尖括号之后,Git 会通知咱们这些改变是从哪里(哪个分支)来的。而后有抵触的改变会被“=======”宰割起来。
当初,当清理文件并失去最终代码后,所有剩下的工作就是将这个后果保存起来,并且马上退出这个合并工具。这样 Git 就会晓得你曾经实现了这个操作。Git 会在后盾对那个文件主动地执行“git add”命令。这也标记着抵触曾经解决了。如果你 应用合并工具,而是手动在文本编辑器中清理这些抵触,你必须手动地将文件标记为已解决状态(通过执行命令“git add”)。

最终,当所有的抵触被解决后,你必须通过一个失常的提交操作来实现这个清理合并抵触的工作。

如何撤销一个合并

你应该始终牢记,你能够在任何工夫执行撤销操作,并返回到你开始合并之前的状态。要对本人有信念,你不会毁坏我的项目中的任何货色。只有在命令行界面中键入“git merge –abort”命令,你的合并操作就会被平安的撤销。

当你解决完抵触,并且在合并实现后发现一个谬误,你依然还是有机会来简略地撤销它。你只须要键入“git reset –hard”命令,零碎就会回滚到那个合并开始前的状态,而后从新开始吧!

git status 会有 rebase in progress; onto ……这种问题?该怎么解决?

是你之前或者刚刚用过 git rebase,但上一次的过程还没有实现。

能够间接 git rebase --abort 来勾销目前的过程

比拟暂存区和 HEAD 所含文件的差别

git diff --cached

比拟工作区和暂存区所含文件的差别

git diff
git diff -- 可加具体文件名

让暂存区复原成和 HEAD 一样

git reset HEAD

让工作区复原为和暂存区一样

git checkout -- 文件名

勾销暂存区局部文件的更改

git reset HEAD -- 文件名

打消最近几次的提交

git reset --hard commitid(想回到的 commit 状态)

查看不同提交的指定文件的差别

git diff 分支名或 commitid 分支名或 commitid -- 指定文件

删除文件的正确做法

git rm 文件名

开发中长期加塞了紧急任务怎么解决

场景: 开发中有一部分文件曾经放到了暂存区, 一部分还在工作区批改当中, 然而测试发现对应的分支是有问题的, 须要长期修复 bug

1. 先把手头的工作备份到其余中央 git stash, 能够用git stash list 查看

2. 修复完 bug 提交后再复原持续

git stash apply stash 列表中寄存的文件仍会保留

git stash popstash 列表中寄存的文件会移除

指定不须要 Git 治理的文件

gitHub 新建仓库时会让你配置一个 .gitignore 文件, 针对不同的语言指定不被 git 治理的文件类型

只能够命名为.gitignore

如 java

# Compiled class file
*.class
# Package Files #
*.jar
*.war
*.tar.gz
*.zip
...

将 Git 仓库备份到本地

罕用的传输协定

哑协定与智能协定

直观区别: 哑协定传输进度不可见, 智能协定可见

传输速度: 智能协定比哑协定块

举荐应用智能协定

备份特点: 多点备份

如果要和远端的仓库进行关联的话, 须要remote

git remote -v 查看
git remote add 名字 地址 新建远端仓库

当本地仓库有新的分支,而远端并未增加进去时,间接 push

git push 远端仓库

Git 近程操作

git clone

近程操作的第一步,通常是从近程主机克隆一个版本库,这时就要用到 git clone 命令。

$ git clone < 版本库的网址 >

比方,克隆 jQuery 的版本库。

$ git clone https://github.com/jquery/jquery.git

该命令会在本地主机生成一个目录,与近程主机的版本库同名。如果要指定不同的目录名,能够将目录名作为 git clone 命令的第二个参数。

$ git clone < 版本库的网址 > < 本地目录名 >

git clone反对多种协定,除了 HTTP(s)以外,还反对 SSH、Git、本地文件协定等

git remote

为了便于管理,Git 要求每个近程主机都必须指定一个主机名。git remote命令就用于治理主机名。

不带选项的时候,git remote命令列出所有近程主机。

$ git remote
origin

应用 -v 选项,能够参看近程主机的网址。

$ git remote -v
origin  git@github.com:jquery/jquery.git (fetch)
origin  git@github.com:jquery/jquery.git (push)

下面命令示意,以后只有一台近程主机,叫做 origin,以及它的网址。

克隆版本库的时候,所应用的近程主机主动被 Git 命名为 origin。如果想用其余的主机名,须要用git clone 命令的 -o 选项指定。

$ git clone -o jQuery https://github.com/jquery/jquery.git
$ git remote
jQuery

下面命令示意,克隆的时候,指定近程主机叫做 jQuery。

git remote show命令加上主机名,能够查看该主机的详细信息。

$ git remote show < 主机名 >

git remote add命令用于增加近程主机。

$ git remote add < 主机名 > < 网址 >

git remote rm命令用于删除近程主机。

$ git remote rm < 主机名 >

git remote rename命令用于近程主机的改名。

$ git remote rename < 原主机名 > < 新主机名 >

git fetch

一旦近程主机的版本库有了更新(Git 术语叫做 commit),须要将这些更新取回本地,这时就要用到 git fetch 命令。

$ git fetch < 近程主机名 >

下面命令将某个近程主机的更新,全副取回本地。

git fetch命令通常用来查看其他人的过程,因为它取回的代码对你本地的开发代码没有影响。

默认状况下,git fetch取回所有分支(branch)的更新。如果只想取回特定分支的更新,能够指定分支名。

$ git fetch < 近程主机名 > < 分支名 >

比方,取回 origin 主机的 master 分支。

$ git fetch origin master

所取回的更新,在本地主机上要用 ” 近程主机名 / 分支名 ” 的模式读取。比方 origin 主机的 master,就要用origin/master 读取。

git branch命令的 -r 选项,能够用来查看近程分支,-a选项查看所有分支。

$ git branch -r
origin/master

$ git branch -a
* master
  remotes/origin/master

下面命令示意,本地主机的以后分支是master,近程分支是origin/master

取回近程主机的更新当前,能够在它的根底上,应用 git checkout 命令创立一个新的分支。

$ git checkout -b newBrach origin/master

下面命令示意,在 origin/master 的根底上,创立一个新分支。

此外,也能够应用 git merge 命令或者 git rebase 命令,在本地分支上合并近程分支。

$ git merge origin/master
# 或者
$ git rebase origin/master

下面命令示意在以后分支上,合并origin/master

git pull

git pull命令的作用是,取回近程主机某个分支的更新,再与本地的指定分支合并。它的残缺格局稍稍有点简单。

$ git pull < 近程主机名 > < 近程分支名 >:< 本地分支名 >

比方,取回 origin 主机的 next 分支,与本地的 master 分支合并,须要写成上面这样。

$ git pull origin next:master

如果近程分支是与以后分支合并,则冒号前面的局部能够省略。

$ git pull origin next

下面命令示意,取回 origin/next 分支,再与以后分支合并。本质上,这等同于先做git fetch,再做git merge

$ git fetch origin
$ git merge origin/next

在某些场合,Git 会主动在本地分支与近程分支之间,建设一种追踪关系(tracking)。比方,在 git clone 的时候,所有本地分支默认与近程主机的同名分支,建设追踪关系,也就是说,本地的 master 分支主动 ” 追踪 ”origin/master分支。

Git 也容许手动建设追踪关系。

git branch --set-upstream master origin/next

下面命令指定 master 分支追踪 origin/next 分支。

如果以后分支与近程分支存在追踪关系,git pull就能够省略近程分支名。

$ git pull origin

下面命令示意,本地的以后分支主动与对应的 origin 主机 ” 追踪分支 ”(remote-tracking branch)进行合并。

如果以后分支只有一个追踪分支,连近程主机名都能够省略。

$ git pull

下面命令示意,以后分支主动与惟一一个追踪分支进行合并。

如果合并须要采纳 rebase 模式,能够应用 --rebase 选项。

$ git pull --rebase < 近程主机名 > < 近程分支名 >:< 本地分支名 >

如果近程主机删除了某个分支,默认状况下,git pull 不会在拉取近程分支的时候,删除对应的本地分支。这是为了避免,因为其他人操作了近程主机,导致 git pull 人不知; 鬼不觉删除了本地分支。

然而,你能够扭转这个行为,加上参数 -p 就会在本地删除近程曾经删除的分支。

$ git pull -p
# 等同于上面的命令
$ git fetch --prune origin 
$ git fetch -p

git push

git push命令用于将本地分支的更新,推送到近程主机。它的格局与 git pull 命令相仿。

$ git push < 近程主机名 > < 本地分支名 >:< 近程分支名 >

留神,分支推送程序的写法是 < 起源地 >:< 目的地 >,所以 git pull 是 < 近程分支 >:< 本地分支 >,而 git push 是 < 本地分支 >:< 近程分支 >。

如果省略近程分支名,则示意将本地分支推送与之存在 ” 追踪关系 ” 的近程分支(通常两者同名),如果该近程分支不存在,则会被新建。

$ git push origin master

下面命令示意,将本地的 master 分支推送到 origin 主机的 master 分支。如果后者不存在,则会被新建。

如果省略本地分支名,则示意删除指定的近程分支,因为这等同于推送一个空的本地分支到近程分支。

$ git push origin :master
# 等同于
$ git push origin --delete master

下面命令示意删除 origin 主机的 master 分支。

如果以后分支与近程分支之间存在追踪关系,则本地分支和近程分支都能够省略。

$ git push origin

下面命令示意,将以后分支推送到 origin 主机的对应分支。

如果以后分支只有一个追踪分支,那么主机名都能够省略。

$ git push

如果以后分支与多个主机存在追踪关系,则能够应用 -u 选项指定一个默认主机,这样前面就能够不加任何参数应用git push

$ git push -u origin master

下面命令将本地的 master 分支推送到 origin 主机,同时指定 origin 为默认主机,前面就能够不加任何参数应用 git push 了。

不带任何参数的 git push,默认只推送以后分支,这叫做 simple 形式。此外,还有一种 matching 形式,会推送所有有对应的近程分支的本地分支。Git 2.0 版本之前,默认采纳 matching 办法,当初改为默认采纳 simple 形式。如果要批改这个设置,能够采纳git config 命令。

$ git config --global push.default matching
# 或者
$ git config --global push.default simple

还有一种状况,就是不论是否存在对应的近程分支,将本地的所有分支都推送到近程主机,这时须要应用 --all 选项。

$ git push --all origin

下面命令示意,将所有本地分支都推送到 origin 主机。

如果近程主机的版本比本地版本更新,推送时 Git 会报错,要求先在本地做 git pull 合并差别,而后再推送到近程主机。这时,如果你肯定要推送,能够应用 --force 选项。

$ git push --force origin 

下面命令应用 --force 选项,后果导致近程主机上更新的版本被笼罩。除非你很确定要这样做,否则应该尽量避免应用 --force 选项。

最初,git push不会推送标签(tag),除非应用 --tags 选项。

$ git push origin --tags
正文完
 0