Git

Git

部分来源:狂神聊Git

git官方文档

Git基本理论

三个区域

Git本地有三个工作区域:工作目录(Working Directory)、暂存区(Stage/Index)、资源库(Repository或Git Directory)。如果在加上远程的git仓库(Remote Directory)就可以分为四个工作区域。文件在这四个区域之间的转换关系如下:

图片

  • Workspace:工作区,就是平时存放项目代码的地方,即git文件

  • Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息

  • Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本

  • Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换

本地的三个区域确切的说应该是git仓库中HEAD指向的版本:

图片

  • Directory:使用Git管理的一个目录,也就是一个仓库,包含我们的工作空间和Git的管理空间。

  • WorkSpace:需要通过Git进行版本控制的目录和文件,这些目录和文件组成了工作空间。

  • .git:存放Git管理信息的目录,初始化仓库的时候自动创建。

  • Index/Stage:暂存区,或者叫待提交更新区,在提交进入repo之前,我们可以把所有的更新放在暂存区。

  • Local Repo:本地仓库,一个存放在本地的版本库;HEAD会只是当前的开发分支(branch)。

  • Stash:隐藏,是一个工作状态保存栈,用于保存/恢复WorkSpace中的临时状态。

工作流程

git的工作流程一般是这样的: 1、在工作目录中添加修改文件; 2、将需要进行版本管理的文件放入暂存区域; 3、将暂存区域的文件提交到git仓库。

因此,git管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)

图片

工作区和暂存区

git-repo

  • 版本库是工作区中的隐藏目录文件.git,版本库中最重要的是stage暂存区;此外git还自动创建了第一个分支master和指针HEAD

  • 文件修改先通过add添加到stage暂存区,然后再统一使用commit提交到主分支,并清空暂存区

管理修改

分支管理

每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。

对不同分支的操作实际上是对不同指针的操作,所以速度很快

git-br-initial

  • 目前只有一条时间线,即主分支(master分支),HEAD指针指向mastermaster指向提交。每次提交master分支都会向前移动一步。

git-br-create

git-br-dev-fd

  • 创建一个新分支dev(即增加一个指针),再改变HEAD的指向,对工作区的修改和提交就是针对dev分支了

git-br-ff-merge

  • 合并分支时,只需要将master指向当前dev所指的位置,就完成了合并;删除分支时也只需要删除指针即可。

git-br-feature1

  • 当分别对feature1master进行不同的修改merge合并,会发生冲突,git status中也会提示。此时查看文件,Git用<<<<<<<=======>>>>>>>标记出不同分支的内容,进行修改后再提交

git-br-conflict-merged

  • 最后再删除feature1分支即可

合并有冲突时,会将冲突的内容写入到你的文件中,你解决冲突就是改这个文件,然后 add commit ,这就完成了一次合并时冲突的解决过程

分支策略

  1. master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活

  2. dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

  3. 每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

git-br-policy

多人协作

多人协作的工作模式:

  1. 首先,可以试图用git push origin <branch-name>推送自己的修改

  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;

  3. 如果合并有冲突,则解决冲突,并在本地提交;

  4. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

Git项目搭建

配置Git

#查看系统config
$ git config --system --list
#查看当前用户(global)配置
$ git config --global --list

#设置用户名和邮箱(必要)
$ git config --global user.name "Colin13" #名称
$ git config --global user.email 1002667204@qq.com #邮箱

创建本地仓库

#新建一个空目录并在目录下输入
$ git init

克隆远程仓库

#会克隆项目和整个代码历史(版本信息)
$ git clone https://gitee.com/kuangstudy/openclass.git

文件添加到Git仓库

#首先需要在Git仓库文件夹中创建文件readme.txt
$ git add readme.txt #第一步:git add 将文件修改添加到暂存区
$ git commit -m "worte a readme file for testing" #第二步:git commit 将文件修改提交到当前分支,-m 后是对本次提交的说明,可以记录每次改动的信息

# 修正错误的commit
$ git commit -m 'new commit'
$ git commit --amend #重新提交:提交暂存区的文件,并用新的一次提交覆盖上一次的提交信息。

为什么添加到Git仓库要分成两步?

commit可以一次提交多个文件,所以可以多次使用add添加最后再用commit统一提交

查看工作区状态及修改内容

#对readme.txt文件进行一些修改
$ git status #查看工作区的状态,会提示文件修改且未提交
$ git diff #查看修改内容

版本回退

$ git log #查看提交日志(顺序为从近到远)
#版本回退:
$ git reset --hard HEAD^ #将当前版本退回上一个版本(HEAD指针指向上一个版本)
#回退后再恢复:
$ git reflog #查看每一次历史修改的commit id(历史文件的版本号)
$ git reset --hard 1094a #恢复到1094a对应的版本

Screen Shot 2022-03-08 at 4.00.03 PM

撤销修改

  • 如果文件修改只在工作区内进行,未add到暂存区:

$ git checkout -- readme.txt #将readme.txt在工作区的修改全部撤销,--表示本分支
  • git checkout:用版本库的版本替换工作区的版本

  • 使用git checkout -- readme.txt撤销修改会有两种情况:

    1. readme.txt修改后还没有add到暂存区,这时撤销修改会回到和版本库相同的状态

    2. readme.txtadd到暂存区后又进行了修改,现在撤销修改会回到刚add到暂存区的状态

  • 谨慎使用这个命令,因为所有本地的修改都会丢失(git中只有已提交的才能恢复)

 

$ git reset HEAD readme.txt #将readme.txt退回工作区,此时暂存区被清空,工作区有修改
$ git checkout -- readme.txt #再用上文的命令撤销工作区的修改

删除文件

$ rm readme.txt #在工作区中删除文件(这一步也可以省略)
$ git rm readme.txt #将删除操作提交到暂存区

$ git restore --staged readme.txt #撤销提交到暂存区的删除操作,或
$ git commit -m "remove readme.txt" #将删除操作commit到版本库,彻底删除文件(无法找回)

只要删除操作没有被commit到版本库,都可以通过git checkout恢复到最新的版本

远程仓库

 

GitHub

  • 在GitHub账户设置添加本地.ssh文件夹中的id_rsa.pub公钥

  • GitHub新建仓库

  • 上传本地仓库或创建新仓库,认将远程库命名为origin

本地仓库上传时出现src refspec main does not match any错误:本地仓库中没有文件,本地添加READMEcommit后再上传

 

添加远程仓库

$ git remote add <shortname> <url>

克隆远程库

自动将其添加为远程仓库并认以 “origin” 为简写

认情况下,git clone 命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或其它名字的认分支)。 运行 git pull 通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。

$ git clone git@github.com:michaelliao/gitskills.git
$ git pull

查看远程仓库信息

这个命令会列出远程仓库的 URL 与跟踪分支的信息,当你在特定的分支上执行 git push自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了, 还有当你执行 git pull 时哪些本地分支可以与它跟踪的远程分支自动合并。

# git remote show <remote>
$ git remote show origin

拉取某个仓库的数据

访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。

git fetch 命令只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。

# git fetch <shortname>
$ git fetch origin

推送本地更新

# git push <remote> <branch>
$ git push origin master #将本地master分支的最新修改推送至远程库
$ git push origin master:awesomebranch #将本地的master分支推送至远程库的awesomebranch分支

重命名远程仓库

修改远程仓库的简写名

# git remote rename <oldname> <newname>
$ git remote rename pb paul

移除远程库

(这里只是解绑,彻底删除库需要在GitHub网站上进行):

$ git remote -v #查看远程库信息
$ git remote rm origin #解除本地和远程的绑定关系(但不会删除远程库)

 

分支管理

创建与合并分支

# 创建分支
$ git branch dev #创建dev分支
$ git checkout -b dev #创建分支并切换到该分支,此后提交都在该分支上

# 查看分支
$ git branch #查看当前分支(列出所有分支,当前分支前会标*)

# 切换分支
$ git checkout master #切换回主分支

# 合并分支
$ git checkout master #先切换到想合并入的分支
$ git merge dev #将dev分支合并到主分支,认为Fast forward策略

# 删除分支
$ git branch -d dev #删除dev分支

分支合并策略

无冲突的分支合并

fast-forward:当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧,这就叫做 “快进(fast-forward)”。

如果开发历史从一个更早的地方开始分叉开来(diverged)时,Git 会使用两个分支的末端所指的快照(C4C5)以及这两个分支的公共祖先(C2),做一个简单的三方合并。

一次典型合并中所用到的三个快照。

有冲突的分支合并

如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,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

## 可以将文件修改为下面这样以解决冲突

<div id="footer">
please contact us at support@github.com
</div>

或者也可以使用图形化工具来解决冲突

$ git mergetool

解决冲突后,重新将该文件添加到暂存区并commit即可

$ git add <filename>

 

分支管理策略

$ git branch 										#查看当前所有分支列表
$ git branch -v #查看每一个分支的最后一次提交
$ git branch --merged #查看哪些分支已经合并到当前分支
$ git branch --merged master #查看已合并到master的分支
$ git branch --no-merged #查看所有包含未合并工作的分支
$ git branch --no-merged master #查看尚未合并到master的分支

$ git branch -D test #强制删除test分支(包含未合并工作时-d删除会出错,要使用-D强制删除

$ git log --oneline --decorate #查看各个分支当前所指的对象、提交记录
$ git log --oneline --decorate --graph --all #以图的形式查看提交历史、各个分支的指向以及项目的分支分叉情况。

$ git merge --no-ff -m "merge with no-ff" dev
#禁用Fastforward策略,以普通模式合并,因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

 

不使用Fast forward模式,merge后会形成和解决冲突后相同的分支情况:

git-no-ff-mode

 

分支开发工作流

长期分支:在整个项目开发周期的不同阶段,你可以同时拥有多个开放的分支;你可以定期地把某些主题分支合并入其他分支中。

许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在 master 分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop 或者 next 的平行分支,被用来做后续开发或者 测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了。 这样,在确保这些已完成的主题分支(短期分支,比如之前的 iss53 分支)能够通过所有测试,并且不会引入更多 bug 之后,就可以合并入主干分支中,等待下一次的发布。

稳定分支的指针总是在提交历史中落后一大截, 而前沿分支的指针往往比较靠前。

你可以用这种方法维护不同层次的稳定性。 一些大型项目还有一个 proposed(建议) 或 pu: proposed updates(建议更新)分支,它可能因包含一些不成熟的内容而不能进入 next 或者 master 分支。 这么做的 目的是使你的分支具有不同级别的稳定性;当它们具有一定程度的稳定性后,再把它们合并入具有更高级别稳定 性的分支中。 再次强调一下,使用多个长期分支的方法并非必要,但是这么做通常很有帮助,尤其是当你在一 个非常庞大或者复杂的项目中工作时。

截屏2022-08-25 22.17.50

远程分支

远程分支以<remote>/<branch>的形式命名,如origin/master,表示远程库origin上的master分支(origin是clone时git对远程服务器的认命名,可以通过git clone -o <remote>自定义

克隆完成后本地会有masterorigin/master两个指针

克隆之后的服务器与本地仓库。

$ git ls-remote <remote>	#显式获得远程引用的完整列表

$ git remote show <remote> #获得远程分支的更多信息

$ git remote add <shortname> <url> #添加新的远程仓库

 

当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。本地的分支并不会自动与远程仓库同步——你必须显式地推送想要分享的分支。 这样,你就可以把不愿意分享内容放到私人分支上,而将需要和别人协作的内容推送到公开分支。

跟踪分支

一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”(它跟踪的分支叫做“上游分支”)。 跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入 git pull,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。

如果你尝试检出的分支不存在且刚好只有一个名字与之匹配的远程分支,那么 Git 就会为你创建一个跟踪分支

# 将本地分支设置为与上游分支不同的名字
$ git checkout -b sf origin/serverfix #本地创建一个和远程分支名字不同的跟踪分支
# 更改当前分支跟踪的上游分支
$ git branch -u origin/serverfix #设置跟踪的上游分支为origin/serverfix
$ git branch --set-upstream-to origin/serverfix #-u == --set-upstream-to
# 查看本地分支跟踪的远程分支,以及本地分支的版本情况

相关文章

本篇内容主要讲解“gitee如何上传代码”,感兴趣的朋友不妨来...
这篇“从gitee上下的代码如何用”文章的知识点大部分人都不太...
这篇文章主要介绍“gitee如何下载仓库里的项目”,在日常操作...
本篇内容主要讲解“怎么在Gitee上更新代码”,感兴趣的朋友不...
本文小编为大家详细介绍“怎么将工程托管到gitee”,内容详细...
这篇文章主要介绍了gitee中图片大小如何调整的相关知识,内容...