Git 的正确使用姿势与最佳实践:团队协作和版本控制的最佳实践 | 青训营

366 阅读25分钟

Git 的正确使用姿势与最佳实践

前言

笔者环境

  • macos 10.15.7

  • git 2.36.1

读完本文可以获得

  • Git的基本概念和工作流程
  • Git的常见命令操作与实践
  • Git的分支、标签等高级功能
  • Git在团队协作中的最佳实践

引用

本文内容较长,如只需简单了解使用流程,请查看2.9 常用Git使用流程

一、Git介绍

1.1 Git是什么

Git是一款分布式版本控制系统,用于跟踪和管理软件开发项目中的代码变更,支持多人协作、版本管理和代码历史追踪。

分布式

采用分布式架构的版本控制系,每个开发者在本地都有完整的代码仓库副本,服务器宕机不会影响开发。

版本控制

一种记录和管理文件变化的方法,让你可以追踪文件的修改历史并在需要时返回到之前的状态。

1.2 为什么使用Git

使用Git可以让团队成员更好地协同开发(多个人一起写代码而不混乱),就像在云端上共享文件夹一样,随时跟踪谁修改了什么,方便回滚和合并,避免混乱和丢失。

1.3 RCS&SVN&Git

以下是RCS(Revision Control System)、SVN(Apache Subversion)和Git在一些特性的比较:

特性RCSSVNGit
存储方式文件目录分布式仓库
架构集中式集中式分布式
分支管理无分支目录级分支强大的分支管理
代码历史有限的历史追踪能力完整的历史记录,但依赖于中央服务器完整的本地和远程历史记录,独立于中央服务器
网络依赖度无,本地操作需要连接到中央服务器本地操作,不需要频繁网络连接
性能慢,每次都要复制整个项目较慢,需要网络连接快速,本地操作,只传输变更数据
优点/支持大文件分布式,强大分支管理,强完整性
缺点单文件,不支持分支集中化,单点故障学习成本高,大文件的支持不好(git-lfs工具可以弥补)

RCS只能进行文件级版本控制,不支持目录和分支。

SVN改进为目录级版本控制,但是集中化架构,对网络依赖性高。

Git采用分布式架构,实现了强大的分支管理、本地操作等功能,是当前最流行的选择。

1.4 安装

Git - 安装 Git (git-scm.com)

1.5 配置 SSH 连接 GitHub

  1. 生成新的 SSH 密钥并将其添加到 ssh-agent
  2. 新增 SSH 密钥到 GitHub 帐户
  3. 测试 SSH 连接

二、Git基本使用方式

2.1 基本命令

Screen Shot 2023-08-21 at 6.59.37 PM.png

2.2 Git目录介绍

2.2.1 项目初始化

mkdir gitDemo
cd gitDemo
git init

Screen Shot 2023-08-21 at 7.08.18 PM.png

通过使用git init命令,我们创建了一个新的git仓库,且当前分支是master

其他参数

  • --initial-branch 初始化某个分支
  • --bare 创建一个裸仓库(纯Git目录,没有工作目录),用来存储版本历史和元数据。
  • --template通过模板创建Git仓库

2.2.2 Git 目录

使用tree .git,查看.git目录

Screen Shot 2023-08-21 at 7.17.28 PM.png

.git 目录是 Git 在本地存储版本控制元数据和对象的位置。下面来解释一下其中几个重要的目录和文件:

  • HEAD: 指向当前分支
  • config: 本地 Git 配置
  • hooks: 存放客户端或服务端钩子脚本
  • objects: 存放所有对象内容,包括 commit、Tree、Blob 等对象
  • info/exclude: ignore 规则配置
  • refs/heads: 本地分支引用
  • refs/tags: 标签引用

其中,objects目录非常重要,它存放了Git中的核心数据。其中主要有三类对象:

  • Commit 对象: 表示一次提交,包含提交信息、作者、指向Tree对象的引用等元数据。

  • Tree 对象: 表示目录结构,包含Tree的模式、名字、指向 Blob对象或子树的引用等信息。

  • Blob 对象: 表示Git存储文件快照的形式,包含文件内容。

2.2.4 Git Config

Git的配置主要通过git config命令来管理。git config可以在系统级、全局级和仓库级进行配置。

  1. 系统级配置:作用于所有用户和仓库,通常存放在/etc/gitconfig文件中。可以使用--system选项设置:
    git config --system user.name "name"
  1. 全局级配置:作用于当前用户的所有仓库,通常存放在~/.gitconfig文件中。可以使用--global选项设置:
    git config --global user.email "email" 
  1. 仓库级配置:只作用于当前仓库,通常存放在仓库的.git/config文件中。可以直接使用git config命令设置:
git config user.name "name"

常见的配置项有:

  • user.name:设置用户名
  • user.email:设置用户邮箱
  • core.editor:设置默认文本编辑器
  • color.ui:设置Git命令行颜色

配置的优先级依次为:仓库级 > 全局级 > 系统级。每个级别的配置重复,但是低级别的配置会覆盖高级别的配置。

我们可以通过git config --list命令查看全局和系统配置。通过cat .git/config可以查看当前仓库的配置。

2.3 Git Remote

git remote 命令用于管理本地仓库配置的远程仓库服务器,经常用来添加、修改、查看和删除远程版本库。

2.3.1 添加远程版本库

# 使用 SSH 协议添加一个远程版本库,命名为 origin_ssh
git remote add origin_ssh  git@github.com:samuelZhang7/gitDemo.git
# 使用 HTTP 协议添加一个远程版本库,命名为 origin_http
git remote add origin_http https://github.com/samuelZhang7/gitDemo.git 
  • 使该仓库同时支持 SSH 和 HTTP 两种协议访问远程仓库。
  • SSH 协议需要生成密钥,但更安全。HTTP 协议更方便,但相对来说不太安全。

2.3.2 修改远程版本库

# 修改 origin_http 的仓库地址地址
git remote set-url origin_http https://github.com/samuelZhang7/repo.git  

2.3.3 删除远程版本库

# 删除名称为 origin_http 的远程版本库的引用
git remote remove origin_http

具体来说,git remote remove origin_http 会做以下几件事:

  1. 在本地仓库的 .git/config 文件里删除 origin_http 的配置信息。
  2. 不再跟踪 origin_http 对应的远程仓库,本地也不再自动维护 origin_http 的引用信息。
  3. 本地已经获取的远程库数据会保留在本地,不会被删除。
  4. 本地的分支(如master)不受影响。
  5. 以后就无法通过origin_http 推送或拉取远程仓库了。

该命令只会删除本地对远程 origin_http 的引用记录,不会删除本地缓存的远程库数据,远程仓库本身也不会受影响。

2.3.4 查看远程版本库

# 列出所有远程库的名称
spaceqi@macbookpro .git % git remote
origin_ssh

# 显示所有远程库的fetch和push地址 (-v 显示详细信息)
spaceqi@macbookpro .git % git remote -v
origin_ssh	git@github.com:samuelZhang7/gitDemo.git (fetch)
origin_ssh	git@github.com:samuelZhang7/gitDemo.git (push)

2.4 Git 工作流程

2.4.1 工作区&暂存区&本地仓库&远程仓库

13d07db5230745799156dcfdf14792f7.png

工作区: 就是你在电脑里能看到的项目目录。

比如有README.md和src代码文件夹。在工作区你可以任意修改文件。比如我们当前在./gitDemo目录下。

暂存区: 可以想象成一个临时保存修改的地方。

当你在工作区修改文件后,需要先把文件添加到暂存区,等准备好了再提交。

本地仓库: 就像一个代码库,已经提交到本地仓库的文件会被Git永久保存起来。

每次提交会记录快照和日志。

远程仓库: 类似一个网盘,比如github、gitlab。

本地仓库的文件可以推送到远程仓库,这样多个人可以访问。

2.4.2 一般工作流程

  1. 在工作区修改文件

  2. 将修改的文件添加到暂存区

  3. 从暂存区提交修改到本地仓库

  4. 从本地仓库推送更新到远程仓库

在这个过程中,Git让你可以确切地控制什么文件提交,并且可以记录每一个版本。

2.5 Git Add

git add命令用于将工作区(workspace)的变更添加到暂存区(stage)。

2.5.1 基本用法

  • git add <file>:添加指定文件
  • git add *:添加所有变更过的文件
  • git add .:添加当前目录下所有变更过的文件
  • git add -p:交互式添加文件

git add不会影响工作区中的文件内容,仅仅将快照添加到暂存区。

git rm --cached <file> 从暂存区删除文件,以取消暂存区

2.5.2 案例演示

Screen Shot 2023-08-22 at 4.21.57 PM.png

上述执行了以下操作

  1. 新增文件readme.md,但还未跟踪(untracked)
  2. 使用git add . 将gitDemo目录下的所有变更的文件(此处只有readme.md一个文件)添加到暂存区
  3. 修改了readme.md文件的内容,但未暂存修改
  4. 使用git add readme.md,将修改后的文件重新添加到暂存区

2.6 Git Commit

git commit命令用于提交暂存区的快照到本地仓库。

2.6.1 git commit的常用选项

  • -m:添加本次提交的说明信息。

    git commit -m "修改了README文件"  
    
  • -a:直接把所有已经跟踪过的文件暂存上,并提交。跳过git add步骤。

  • --amend:修改最后一次提交信息,常用于提交前修改提交信息。

  • --no-edit:使用上次的提交信息,跳过修改提交信息的步骤。

提交的内容来源于当前暂存区快照,提交后会包含这个快照的元数据和内容。

2.6.2 案例演示

Screen Shot 2023-08-22 at 4.29.50 PM.png

使用git commit命令提交暂存区的快照到提交到本地仓库,并添加说明信息,提交之后,使得暂存区成为空,即干净的暂存区。

2.7 Git Clone&Pull&Fetch

Git中的克隆(Clone)、拉取(Pull)和获取(Fetch)用于从远程仓库获取代码。

2.7.1 Git Clone

  • 完整地克隆一个远程仓库,生成一个本地目录(包含远程仓库所有的历史提交)
  • 会自动创建origin remote,指向克隆的远程仓库
  • 一般用于从无到有创建一个本地仓库副本

2.7.2 Git Pull

  • 拉取远程最新代码并合并到本地分支
  • 就是git fetch+git merge的组合,可能会出现冲突,需要解决冲突
  • 一般用于持续从远程获取更新并合并到本地

2.7.3 Git Fetch

  • 获取远程最新代码到本地,但不进行合并
  • 获取远程仓库的所有分支更新,存储在本地的origin/分支
  • 一般用于从远程获取最新代码而不直接合并

简单来说,Clone用于新建本地仓库,Pull用于持续更新本地代码,Fetch用于获取远程更新但不立即合并。

2.8 Git Push

git push命令用于将本地分支的代码,推送到远程仓库。

2.8.1 git push的常见用法

  • git push origin master:将本地master分支推送到origin远程仓库
  • git push -u origin master:同时将master设置为默认上游分支
  • git push:将当前分支推送到已配置的上游分支(等价于上例)
  • git push origin --tags:推送所有本地新增的标签
  • git push origin :branchName:删除远程仓库的分支

2.8.2 注意事项

  • git push不会推送未被提交的更改。

  • 远程仓库没有推送的分支,将会新建一个分支

  • 本地仓库比远程新(本地仓库拥有远程仓库所有的文件,且有新增的文件),git push 可以直接推送

  • 远程仓库比本地新(远程仓库有新的文件,而本地仓库没有),需要先拉取最新的仓库,再解决冲突,然后再推送

2.8.3 案例演示

Screen Shot 2023-08-22 at 4.55.34 PM.png

通过ssh协议将本地仓库推送到origin_ssh远程仓库。

2.9 常用Git使用流程

1. 将项目代码克隆到本地

使用git clone命令克隆远程仓库,这会在本地创建一个仓库的拷贝,包含远程仓库的代码、全部历史记录;并且程仓库origin会被自动添加。

git clone https://github.com/samuelZhang7/gitDemo.git

2. 在本地开发并提交修改

在本地克隆的仓库中修改代码,使用git addgit commit命令来提交修改。

# 添加修改
git add . 

# 提交修改  
git commit -m "修改说明"

3. 查看修改记录

使用 git log 命令查看历史提交记录,可以看到新增的提交。

git log

4. 从远程仓库拉取最新代码

使用 git pull 命令从远程仓库拉取最新代码,并自动merge到本地分支,解决可能出现的代码冲突。

git pull origin master

5.将本地提交推送至远程仓库

使用 git push 命令将本地的提交推送到远程仓库,与团队成员共享修改。

git push origin master

三、Git进阶

3.1 Objects

Objects 是组成 Git 版本控制系统的核心数据,保存在 .git/objects 目录下,对象的命名使用 hash 函数的前几位。

3.1.1 三类 Objects

Blob 对象(Blob Object)
  • 存储文件内容,是一个二进制文件

  • 文件内容使用 SHA-1 哈希算法生成 hash 值来命名和定位

Tree 对象(Tree Object)
  • 存储文件的目录信息

  • Tree 对象可以包含其他 Tree 对象,实现目录嵌套

Commit 对象(Commit Object)
  • 存储提交信息,包含提交注释、作者、指向 Tree 对象的指针

  • 一个Commit对应唯一版本的代码

3.1.2 如何将三者信息串联在一起

1. 初始化本地仓库

Screen Shot 2023-08-22 at 5.40.48 PM.png

我们新建objectsDemo项目,没有将文件提交到本地仓库,因此objects目录下没有object(即对象),refs\heads目录下也没有文件。

2. 新增一个commit

Screen Shot 2023-08-22 at 5.44.22 PM.png

  • 当新增一个文件并提交时,objects目录中会新增3种object来表示此次变更,因此objects目录下会出现3个新的object,即Blob对象、Tree对象、Commit对象。
  • 其中233b e6是object对象内容的完整SHA-1值的前两位,而它们目录下的文件名,则是完整的40位哈希值。
  • 一个object的name是该对象内容的SHA-1哈希值的前X位+后Y位哈希值。

那如何知道这3个object是什么类型呢?

3. 查看object的内容

使用 git cat-file -p <object name>命令查看object的内容

Screen Shot 2023-08-22 at 6.04.08 PM.png

  • 3b1cde591b34736c349420d28e9d872a70f6cc7c 内容显示是一个commit对象,它包含
    • 提交信息<samuelZhang7@outlook.com>
    • 作者zhang qi
    • 提交时间1692697443 +0800
    • Tree对象的引用239ec593c6a2192e76c005435f748b2ad28be832
  • 239ec593c6a2192e76c005435f748b2ad28be832 的内容显示是一个Tree对象,它包含
    • 文件名readme.md
    • 文件权限100644
    • Blob对象的引用e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
  • e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 的内容为空,因为我们并没有在readme.md文件中存储任何内容
    • 说明它是一个Blob对象,用于存储文件内容本身。
5. commit-id

3b1cde591b34736c349420d28e9d872a70f6cc7c指向的是一个Commit对象,我们通常称这个哈希值为commit-id或Commit对象引用。

类似的还有tree-id(Tree对象引用)和blob-id(Blob对象引用)

4. 串联关系
  1. 通过commit-id的tree-id,找到目录结构Tree信息,每个Commit对象都包含一个tree-id。
  2. 再通过Tree对象里的blob-id找到Blob信息,每一个Tree对象都包含多个blob-id。
  3. 最后通过Blob对象引用查找到文件的内容

Screen Shot 2023-08-22 at 7.16.35 PM.png

这样由Commit对象串联Tree对象和Blob对象,可追踪一个提交的完整文件快照。

3.2 Branch

Git中的分支(Branch)是独立的开发路径,允许开发者在不影响主代码的情况下创建、修改和合并代码,以便实现并行开发和版本管理。

类比:Git里的分支就像是一份完整的菜单副本,允许你在菜单上点选不同的菜品,而不影响其他人的点餐选择,最后可以将各自点选的菜品合并到一张菜单上。

在Git中,分支指向一个commit-id,默认的分支名称为master

3.2.1 分支分类

  • 主分支(Main Branch): 通常称为“主分支”,即master分支,是项目的核心分支,保存了稳定的、可发布的代码版本。
  • 特性分支(Feature Branch): 用于开发单独的功能或特性的分支,从主分支分离出来,开发完成后可以合并回主分支。
  • 开发分支(Development Branch): 用于集成多个特性分支的分支,通常用于整合各种特性和修复,最终合并回主分支。
  • 修复分支(Bugfix Branch): 用于修复问题、漏洞或错误的分支,从主分支分离出来,修复完成后可以合并回主分支。
  • 发布分支(Release Branch): 用于准备发布版本的分支,可以在发布前进行测试、修复等操作,最终合并回主分支和其他分支。

3.2.2 常用操作

  1. 查看当前分支
git branch 
  1. 创建新分支
git checkout -b dev
  1. 切换分支
git checkout dev
  1. 合并分支
git checkout master
git merge dev
  1. 删除分支
git branch -d dev
  1. 查看分支日志
git log --graph --all --decorate 
  1. 功能分支工作流
# 创建功能分支,用于用户登录
git checkout -b feature/user-login

# 开发新功能
git add .
git commit -m "新功能"

# 合并到主分支
git checkout master
git merge feature/user-login

3.3 Tag

在Git中,标签(Tag)是用于标识稳定的版本,指向一个commit-id,通常指向的Commit一般不会变更。

3.3.1 轻量标签&附注标签

Git中的标签有两种类型:轻量标签(Lightweight Tag)和附注标签(Annotated Tag)。

  1. 轻量标签(Lightweight Tag

    轻量标签实际是指向将当前分支所指向的commit-id

    git tag v0.1.0 
    
  2. 附注标签(Annotated Tag)

    附注标签与轻量标签的区别是前者包含一些额外的信息,如标签名、标签作者、标签日期等元数据的完整对象。

    附注标签通常用于重要的版本发布,以及需要更多信息的情况。

    git tag -a v1.0.0 -m "Release version 1.0.0"
    

    创建附注标签时,会创建一个包含这些信息的单独的Commit对象。通过使用cat .git/refs/tags/v1.0.0 查看commit-id,它是一个新的Commit。 ![Screen Shot 2023-08-23 at 2.06.48 PM](Git.assets/Screen Shot 2023-08-23 at 2.06.48 PM.png)

3.3.2 常用操作

  1. 添加标签
git tag v1.0
git tag v0.9 <commit-id>
  1. 查看标签
git tag
git show v1.0
  1. 删除标签
git tag -d v0.9
  1. 推送标签到远程
git push origin --tags
  1. 基于v1.0版本创建新分支version1
git checkout -b version1 v1.0
  1. 使用标签发布版本
git tag -a v1.2 -m "release version v1.2"
git push origin v1.2

3.4 Refs

3.4.1 refs/head

当新增一个commit后,refs\heads目录下将会创建或更新当前分支指向的commit-id。

使用cat命令查看 .git/refs/heads/master文件

Screen Shot 2023-08-23 at 1.00.50 PM.png

文件的内容是3b1cde591b34736c349420d28e9d872a70f6cc7c,正是上文提到的commit-id。

因此,refs/heads存储的就是每个分支指向的commit-id。

3.4.2 refs/tags

当新增一个tag后,refs/tags目录下会创建一个tag文件,文件的内容是该tag所指向的一个commit-id。

Screen Shot 2023-08-23 at 2.06.48 PM.png

例如我们添加了v0.1.0标签后,Git会在.git/refs/tags下创建一个v0.1.0文件,内容是tag指向的commit-id,然后我们可以通过commit-id来访问Commit对象。

3.5 追溯历史版本

追溯历史版本是指在Git中查看和浏览代码库过去的提交和变更历史。

3.5.1 git log

使用 git log 命令可以查看提交历史。

默认情况下,它会显示所有分支的提交历史,以及每个提交的作者、日期、提交消息等信息。你可以使用各种选项来过滤和定制显示。

git log
git log --author="John"
git log --since="3 days ago"

3.5.2 git show

使用 git show <commit-id> 命令可以查看单个提交的详细信息,包括提交的变更内容、作者、日期等。

你可以通commit-id或标签来查看特定提交。

git show 3b1cde5...12
git show v1.0.0

3.5.3 git diff

使用 git diff 命令可以比较两个提交之间的差异。

通过将两个commit-id传递给该命令,你可以查看它们之间的代码变更。

git diff 3b1cde5...12 e038323...31

3.5.4 git log --graph

使用 git log --graph 命令可以以图形化方式查看提交历史,显示分支合并、分叉等结构。

git log --graph

3.5.5 git reset

使用git reset 回退到指定版本

  1. Soft Reset

    git reset --soft <commit-id>
    

    这是软重置模式。

    这会将分支引用移动到 <commit-id> 所指向的提交,但不会改变工作区和暂存区。

    这常用于撤销提交,将最新的提交撤回并保留更改。

  2. Mixed Reset

    git reset <commit-id>
    

    默认情况下,git reset 就是混合重置模式。

    它将分支引用移动到 <commit-id> 所指向的提交,同时会清空暂存区,但不会改变工作区。

    这用于取消已暂存的更改。

  3. Hard Reset

    git reset --hard <commit-id>
    

    这是最强烈的重置模式。

    它将分支引用移动到 <commit-id> 所指向的提交,同时会清空暂存区和工作目录,将你的代码库恢复到该提交的状态。

注意
  • 使用 git reset 可能会修改历史,如果在公共分支上使用,请确保了解影响,并避免在已推送的分支上使用。
  • 重置后的更改可能会永久丢失,请谨慎使用。
  • 如果需要撤销远程分支的提交,不推荐使用重置操作,应该使用 git revert 创建新的撤销提交,以保持版本历史的一致性。

3.6 修改历史版本

修改历史版本是指在Git中对过去的提交进行修改或操作。

需要注意的是修改提交历史可能会对协同开发和版本控制造成混乱,因此在进行这种操作时应谨慎考虑。

3.6.1 Amend Commit

使用 git commit --amend 命令可以修改最新的提交,修改之后commit-id会改变。

这通常用于修复提交消息、添加遗漏的文件等。

git add missed-file.txt
git commit --amend

3.6.2 Rebase

使用 git rebase 命令可以将提交历史“重新播放”,将一系列提交应用到另一个基础提交上。

这可以用于合并commit、修改commit message、删除某个commit等。

git rebase -i HEAD~3

执行这个命令后,Git会打开一个编辑器,显示了你最近的3个提交的历史。每个提交都有一个操作(如 pick、reword、edit、squash、fixup 等)和提交的信息。你可以对每个提交进行操作,然后保存并关闭编辑器。

3.6.3 Filter-branch

git filter-branch 命令允许删除所有提交中的某个文件或者全局修改邮箱地址等

这是一种强大的操作,慎用,特别是在共享的分支上。

git filter-branch --tree-filter 'rm -f passwords.txt' HEAD

git filter-branch 会逐个遍历每个提交,并在每个提交上执行 rm -f passwords.txt 表示删除名为 passwords.txt 的文件。

3.7 Git GC

git gc用于优化和清理Git仓库的存储空间。

通常情况下,你不需要手动频繁执行 git gc。Git会自动在需要时触发垃圾回收,例如在执行一些操作(如合并、分支切换等)后。

但在某些情况下,特别是当你删除大量的分支、标签或文件时,手动执行 git gc 可以帮助及时回收存储空间。

git gc

3.8 合并和变基的区别

rebasemerge 都是 Git 中用于整合更改的方法。它们的主要区别在于它们创建的提交历史不同。

当你执行 merge 命令时,Git 会创建一个新的提交,它包含了两个分支的更改。这样,你的提交历史将会有一个分叉点,表示两个分支合并的地方。

而当你执行 rebase 命令时,Git 会将一个分支上的提交取下来,然后重新应用到另一个分支上。这样,你的提交历史将变成一条直线,没有分叉点。

选择使用哪种方法取决于你希望创建怎样的提交历史。如果你希望保留分支的历史信息,可以使用 merge;如果你希望创建一个线性的提交历史,可以使用 rebase

3.9 推送多个模块

1. 多个模块推送一个仓库里

如果路径结构是:

D:
└── projectName
    ├── moduleA
    └── moduleB
    └── .git
    
  1. 确保自己当前所处的目录是D:/projectName/
  2. 确保projectName目录下有.git目录,而其他每一个module里面都没有.git目录

2. 每个模块推送到不同的仓库

如果路径结构是:

D:
└── projectName
    ├── moduleA
    └── moduleB
    └── .git
    
  1. 如果要将moduleA项目推送到指定仓库,确保自己当前所处的目录是D:/projectName/moduleA/
  2. 确保要推送的module里面都有.git目录,且配置好了remote。

3.10 拒绝提交

Git报错信息:Push rejected: Push to origin/master was rejected

原因:远程仓库包含本地尚不存在的提交,也就本地没有包含远程仓库内的所有文件。

解决方案:在推送前,先整合远程变更,即把本地仓库和远程仓库做文件关联

  1. git pull origin master --allow-unrelated-histories

    去远程仓库origin拉取master分支的文件并尝试快速合并到当前分支,而且允许合并两个没有共同历史的分支。

    可能:该命令执行成功后会提示你输入本地合并的提交信息

     请输入一个提交信息以解释此合并的必要性,尤其是将一个更新后的上游分支
    # 合并到主题分支。
    #
    # 以 '#' 开始的行将被忽略,而空的提交说明将终止提交。 
    
    

    使用vim的操作,输入i进入输入状态,输入提交信息,然后输入:wq,退出当前窗口。

    然后远程仓库的master分支的文件将拉取并合并到你本地的仓库

  2. 上述命令执行后如果提示需要调和偏离的分支

    提示:你有偏离的分支,需要指定如何调和它们。你可以在执行下一次
    提示:pull 操作之前执行下面一条命令来抑制本消息:
    提示:
    提示:  git config pull.rebase false  # 合并
    提示:  git config pull.rebase true   # 变基
    提示:  git config pull.ff only       # 仅快进
    提示:
    提示:你可以将 "git config" 替换为 "git config --global" 以便为所有仓库设置
    提示:缺省的配置项。你也可以在每次执行 pull 命令时添加 --rebase、--no-rebase,
    提示:或者 --ff-only 参数覆盖缺省设置。
    fatal: 需要指定如何调和偏离的分支。
    

    则需要设置 git config pull.rebase false ,该命令表示设置 pull.rebase 配置选项的值为 false。这意味着当你执行 git pull 命令时,Git 将使用合并而不是变基来整合远程更改。

四、团队协作和版本控制最佳实践

4.1 Git团队协作最佳实践

  • 团队协作方式

    • owner创建好仓库后,统一给团队成员分配权限,直接在同一个仓库进行开发。
    • owner创建好仓库后,团队成员通过Fork的方式来创建自己的仓库,并在fork的仓库上进行开发

    Screen Shot 2023-08-23 at 4.02.23 PM.png

  • 设置保护分支

    通过设置保护分支,来限制合并和push的策略

    Screen Shot 2023-08-23 at 4.04.55 PM.png

  • 使用分支进行开发,master分支仅用于发布稳定版本

    git checkout -b new-feature
    # 开发新分支
    
    git checkout master 
    # 切换回主分支
    
  • 提交小而完整的单元,语句清晰表明修改目的

    git commit -m "添加了登录验证功能" 
    
  • 单独提交修复Bug,不与其他功能混在一起

    git commit -m "修复了首页图片失效的bug"
    
  • 定期推送和更新代码,保证本地仓库和远程同步

    git pull
    git push origin master
    

  • 合理使用.gitignore,只提交需要的文件

  • 提交前提前更新本地代码至最新,避免不必要的冲突

  • 定期推送和更新代码,保证本地仓库和远程同步

4.2 Git版本控制最佳实践

  • 合理使用Git对象哈希地址,查询历史版本信息

    git show 3fe21b...11 
    # 通过commit hash查看提交信息
    
  • 重构时谨慎处理Git历史,避免数据丢失

    git rebase -i HEAD~5 
    # 交互式rebase修改最近5次commit
    
  • 掌握rebase和merge的区别

    git rebase:重播提交,生成全新的提交树 
    git merge:合并分支,保留全部历史记录
    

  • 定期清理无用分支、提交、对象,避免仓库膨胀

  • 重构时谨慎处理 Git 历史,避免数据丢失

五、总结

  • Git是一个优秀的开源分布式版本控制系统
  • 学习Git,重点是掌握它的核心概念,比如git目录、Objects对象、工作区、暂存区、远程仓库等的作用。
  • 熟练Git基础命令的使用以及常用的工作流程,可以大大提高我们的工作效率。
  • 使用分支、标签等功能来实现独立开发和版本发布。
  • 遵循Git的最佳实践,可以改进协作开发流程。

本文从Git的基础知识出发,由浅入深讲解了Git的核心概念、常用命令、高级功能、最佳实践等内容。希望通过本文可以帮助你对Git有一个由浅入深的理解,并能够运用到实际工作中。