基本概念

  1. 概念

    Git 是一种 分布式版本控制系统(DVCS),用于跟踪文件的更改,特别适用于软件开发。它允许多个开发者协作处理同一个项目,并能有效管理代码的历史记录。

  2. Git 与 GitHub、GitLab 的区别

    GitHub、GitLab 等是 基于 Git 的代码托管平台,允许开发者远程存储和管理 Git 仓库。它提供了一系列协作工具,如 issue 追踪、Pull Request(PR)合并、代码审查等。

  3. SVN 与 Git 的区别

    • SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。

    • Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。

  4. Git 的工作原理

    1)工作区、暂存区和本地仓库

    image-20240617170934979

    • 工作区就是我们在文件资源管理器里面看到的项目文件夹,包含所有的代码和文件。这里的文件可以是新创建的、修改过的,甚至是删除的。但这些更改并不会自动被 Git 追踪,必须手动添加到暂存区。
    • 暂存区是 Git 记录变更的 临时存放区,当你使用 git add 命令时,修改会被加入暂存区,只有暂存区中的内容才能被 git commit 提交到本地仓库。它保存了当前文件的状态,而不会影响其他未暂存的文件。
    • 本地仓库存放的是你所有的提交历史,保存在 .git 目录中。当你运行 git commit 时,暂存区的内容就会被提交到本地仓库,形成一个新的提交记录。这里的文件是 受 Git 版本控制的但还没有推送到远程仓库

    2)本地仓库和远程仓库

    image-20240619105114200

    远程仓即远程仓库是存放在 GitHub、GitLab、Bitbucket 等代码托管平台上的仓库。

初始化配置

  1. 下载安装Git并连接Github

    参考:https://blog.csdn.net/secretstarlyp/article/details/106576882

  2. 配置用户名和邮箱

    后续每一个 Git 提交都会使用这些信息,这样在提交的时候才能识别出来是谁提交的内容。

    1
    2
    3
    4
    git config --global user.name isoda_das
    git config --global user.email xxxxx@qq.com
    # 保存
    git config --global credential.helper store

    这里使用了–global参数,表示该设置为全局配置,对所有仓库有效。如果不设置的话仅对本地仓库有效

  3. 查看配置信息是否生效

    1
    git config --global --list

Git 基础命令

新建Git仓库

新建一个文件夹或现有的文件夹并不是 git 仓库,因为文件夹内不包含 .git 文件夹,没有被 git 管理。

所以可以在你希望使用 git 管理的文件夹下,运行如下命令初始化空的git版本库。

1
git init

初始化完成后,如果在项目文件夹中没有看到 .git 文件夹,则需要开启显示隐藏文件。

记录更新到Git仓库

流程:工作区开发—>将修改后的文件添加到暂存区—>将暂存区的文件记录到版本库

  1. 把工作区变化的文件添加到暂存区

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 将 index.html 添加到暂存区  
    git add index.html

    # 将css目录下一切添加到暂存区
    git add css

    # 添加所有后缀为txt的文件
    git add *.txt

    # 将当前目录下所有变化都暂存
    git add .
  2. 将暂存区内的文件提交到本地仓库

    注意这里不会提交工作区的文件,此处文字说明可以不加引号

    1
    2
    3
    4
    5
    # 直接输入提交信息
    git commit -m "第一次提交"

    # vim输入提交信息
    git commit

    image-20240617165754681

    如果commit中存在一些错误:

    • 在没有推送到远程仓库的情况下:可以通过git commit --amend这个命令来修改最近的commit信息 ,生成一个新的提交替代原有的提交
    • 在已经推送到远程仓库的情况下:可以通过 git revert <commit_hash> 命令来撤销掉这个提交,创建一个新的提交并进行 git push

查看状态

  1. 查看提交记录

    1
    git log

    image-20240617170254390

  2. 查看仓库状态

    1
    git status

    可以看到

    • 绿色:表示已经被添加到暂存区,但未被提交(到本地仓库)
    • 红色:未被跟踪,即没有被添加到暂存区的文件

    image-20240617163425847

  3. 版本差异检查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 比较工作区和暂存区的差异
    git diff
    # 比较工作区和本地仓库的差异
    git diff HEAD
    # 比较暂存区和本地仓库的差异
    git diff --cache
    # 比较两个版本提交记录之间的差异
    git diff 5af90b8 7100ee3
    # 仅比较file.txt的差异内容
    git diff xx file.txt

版本回退

image-20240617171033362

使用git log查看提交历史,前面即历史提交的标识符

image-20240617171207610

1
2
3
4
# 回退上一个版本
git reset --soft HEAD^
# 回退到标识符对应的版本
git reset --soft 5af90b8

删除文件

直接从工作区和暂存区删除,但后续仍然要提交commit

1
git rm file.txt

直接放入回收站的话,注意后续仍要进行add和commit操作

gitignore忽略文件

有些时候,我们可能希望设置不push项目目录下的某些内容上去,如密钥文件等。

创建gitignore文件,在里面写入需要进行忽略的内容

1
2
echo access.log > .gitignore
cat .gitignore

规则:
image-20240619103817870

Git 分支

创建分支

在Git中新建一个项目后,默认有一个分支,即主分支。主分支一般表示项目的稳定版本(已完成的代码),主分支应该包含稳定没有 Bug 的代码,并保持随时可以发布的状态。而 dev是平常用来开发的分支,开发完成后再将 dev 分支合并到 master 分支

对于小型项目来说,只有一个主分支就够用了,每次我们提交都会创建一个commit节点。

1
2
3
git commit -m "c1"
git commit -m "c2"
git commit -m "c3"

上面的命令会创建三个commit节点,此时master分支如下图所示,代码经历了C1,C2,C3这三个版本,且master分支目前指向C3这个提交版本。

img

如果项目功能较复杂,且需要多次提交,不建议在主分支直接修改。主分支上应该只包合并提交,所有的迭代应该都在分支上进行。如果是简单的改动,直接在主分支修改也是可以的。

当有新的功能要开发时,应该新建一个功能分支,比如创建一个名为a的分支,并切换到a分支,命令如下:

1
git checkout -b a

创建新分支时,新分支默认指向的代码提交版本为当前分支所指向的代码提交版本,比如这里新分支a指向的提交将为C3。此时当前分支为a,所指向的提交为C3。

合并分支

如果需要合并experiment分支和master分支

image-20250414155858206

merge方法

  1. 原理

    将两个或多个分支的修改集成到一个新的提交中。在合并时,Git 会首先找到两个分支的共同祖先作为基准点,然后使用三方合并算法来将两个分支的修改合并到一个新的提交中。该算法比较共同祖先和要合并的两个分支之间的差异,然后尝试自动合并这些差异。如果两个分支对同一个文件的不同部分进行了修改,Git 通常能够自动合并这些修改;但如果两个分支对同一文件的同一部分进行了不兼容的修改,就会产生冲突,需要手动解决。

    最后实现的结果:

    image-20250414160821013

  2. 方法

    切换到目标分支(通常是主分支): 在合并之前,确保你已经切换到你希望将其他分支合并到的目标分支。例如,通常我们会将分离出来的开发分支合并到主分支。

    1
    2
    3
    git checkout main

    git switch master

    合并指定分支到当前分支

    1
    git merge <branch>

    后续可以再删除掉 experiment 分支

    1
    git branch -d experiment
  3. 冲突处理

    如果出现了冲突,则修改冲突文件,add然后commit该文件

    1
    2
    3
    # 没有冲突时不需要下方的命令。有冲突时,就修改冲突文件,再add然后commit该文件,如下:
    git add readme.txt
    git commit -m "conflict fixed"

rebase方法

  1. 原理

    首先找到当前分支和目标基底分支的最近共同祖先,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件,接着将当前分支指向目标基底,最后将之前另存为临时文件的修改依序应用到目标基底上。

    最后实现的结果:

    image-20250414161129729

    简单来说,就是提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次,像“重新播放”一样。

  2. 命令

    1
    2
    3
    # 将主题分支<topicbranch>变基到目标分支<basebranch>上。
    # 即提取在<topicbranch>上的补丁和修改,然后在<basebranch>的基础上应用一次。
    git rebase <basebranch> <topicbranch>

    或者

    1
    2
    git switch <topicbranch>
    git rebase <basebranch>

    合并完成后可以删除掉 experiment 分支

    1
    git branch -d experiment
  3. 冲突处理

区别

  1. 原理

    • merge:会创建一个新的合并提交(merge commit),以标记分支合并的时刻。这是一个显式的合并点。
    • rebase:没有合并提交,只是将提交“移动”到目标分支后,历史上看不到合并点。
  2. 历史记录

    • merge:保留了分支的历史记录,包括分支的分叉和合并点。合并提交让历史图呈现出分支结构。
    • rebase:将所有提交按顺序重新应用,消除了分支结构,使得历史记录看起来是线性的。
  3. 使用场景

    • merge:适用于团队合作中,多个开发者并行开发并合并到主分支时。保留所有的开发历史可以帮助回溯。
    • rebase:适用于在个人开发中,确保自己的开发历史更简洁、线性,并且可以在准备将工作合并到主分支之前,整理自己的提交历史。特别适合在需要保持干净、整洁的提交历史时使用。

远程仓库同步

我们上面学习的都是在本地的操作,只是将文件提交到本地仓库,这样并不能实现和其他开发者的同步。我们还需要一个代码托管平台作为远程仓库,比如这里我们选择 Github。

Git 和 Github 的连接在我们前面的初始化配置中已经完成。

将github项目pull到本地

什么是pull:将远程代码仓库中(新)的内容下载到本地,并更新本地代码仓库的内容

第一次pull:

首先需要在本地创建一个空文件夹,作为项目的存放仓库。然后进入该文件夹下,打开Git Bush,输入以下命令将该目录初始化为Git仓库。

1
git init

然后将这个本地仓库连接到Github上的对应项目

1
2
# git remote add 仓库命名 远程仓库地址(github上项目的HTTPS协议地址)
git remote add origin https://github.com/soda-VV/soda-VV.github.io.git

如果不小心填错了,可以使用指令清除地址重新设置

1
git remote remove origin 

同样也可以执行命令查看是否连接成功

1
git remote -v

然后,使用Pull指令拉取代码,从远程源的主分支更新代码到本地

1
2
# git pull origin <branch-name>
git pull origin master

后续拉取github上的更新到本地:

1
git pull origin master

将本地项目push到github

  1. 什么是push:将本地库的内容推送到远程仓库中

  2. 第一次push

    同样的,在本地项目文件夹内初始化Git仓库

    1
    git init

    执行add命令将整个文件夹添加到本地仓库

    1
    git add .

    将这个本地仓库连接到Github上的对应项目

    1
    2
    # git remote add 仓库命名 远程仓库地址(github上项目的HTTPS协议地址)
    git remote add origin https://github.com/soda-VV/soda-VV.github.io.git

    将本地更新后的代码上传到GitHub只需要

    1
    2
    git commit -m "第一次上传"
    git push origin master/main

    注意:

    如果推送失败的话,可以看一下仓库命名(origin)是否出错,或者是分支名称写错了(为main分支)

  3. 后续推送本地库的内容到远程仓库:

    1
    2
    3
    git add .
    git commit -m "第n次上传"
    git push origin master

多人协作

如果在多个远程设备上操作,记得开始进行今日的操作前要先:

1
git pull origin master/main

完成所有操作准备离开时要记得:

1
2
3
git add .
git commit -m ‘xx’
git push origin master

tip: 要保证本地库和server是同步的,不然忘记先pull,若其他远程设备上已经push了新的内容,自己这里是push不上去的,只能进行git pull合并,这个操作还会覆盖你已经更改了的部分,会非常痛苦。

冲突问题

Git冲突通常发生在以下几种情况下:

  1. 拉取远程分支:当从远程仓库拉取分支时,如果本地分支与远程分支有不同的修改,并尝试合并时也可能发生冲突。
  2. 不同合并分支:当两个开发者在不同的分支上进行并行开发,并尝试将分支合并时,如果对同一文件的同一部分进行了修改,就会导致冲突。

拉取远程分支冲突

场景在同一分支上,你本地有未提交的更改,但是别人也修改并 push 到远程了,这种情况下我们如何进行同步呢?

示例: 假设你正在开发一个特性,修改了 file.txt 文件,并且将它提交到本地分支。但是,在你提交后,远程仓库的其他开发者也修改了 file.txt 并提交了他们的更改。当你执行 git pull 拉取远程分支时,就可能会遇到冲突。

解决步骤:

  1. 首先执行 git pull ,Git 会显示冲突的文件,并在冲突的文件中插入标记:

    1
    2
    3
    4
    5
    <<<<<<< HEAD
    你的本地修改
    =======
    远程的修改
    >>>>>>> origin/branch-name
  2. 你需要手动编辑 file.txt,选择保留本地修改、远程修改,或者结合两者的内容。

    删除冲突标记(<<>> 标识)后,保存文件。

  3. 在解决冲突后,使用 git add 将解决后的文件标记为已解决:

    1
    git add file.txt
  4. 最后,执行 git commit 完成合并:

    1
    git commit

如果修改较大且难以手动解决,也可以使用工具如 git mergetool 来辅助解决冲突。

不同分支合并冲突

场景:在多人并行开发时,每个开发者可能会在不同的分支上工作。如果他们修改了相同文件的相同部分,当尝试合并这两个分支时,也可能会发生冲突。

示例:开发者 A 在 feature1 分支上工作,修改了 file.txt 的第 10 行。开发者 B 在 feature2 分支上工作,也修改了 file.txt 的第 10 行。当开发者 A 和 B 都完成了工作并试图将 feature1 合并到 main 分支时,Git 会检测到冲突,因为两人都修改了 file.txt 的相同部分。

解决步骤

  1. 执行 git merge feature1git merge feature2,Git 会检测到冲突并提示哪个文件有冲突。

  2. 与前一种情况类似,你需要手动编辑冲突文件,解决冲突。冲突部分会用 <<<<<<<>>>>>>> 标记出来。

    手动编辑并选择保留的修改,删除标记后,保存文件。

  3. 执行 git add file.txt 将解决冲突的文件标记为已解决。

  4. 最后,提交合并:

    1
    git commit

强制推送本地修改

git 强制推送本地修改的操作通常是使用 git push 命令,并加上 --force(或者简写为 -f)选项。这个操作会将本地仓库的内容强制推送到远程仓库,覆盖远程仓库当前的内容。下面是如何使用强制推送:

1
git push origin <branch_name> --force

注意:在日常工作中我们是不推荐 git -f ,为什么:

强制推送会覆盖远程仓库中的内容,如果是多人开发的情况下,可能会覆盖掉他人的工作。

参考文章