一、Git的简介

Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。

Git 工作区、暂存区和版本库、本地仓库的概念:

  • 工作区: 电脑里能看见(非隐藏)的工作目录。
  • 暂存区: 英文叫 stage index暂存区域是一个文件,保存了下次将提交的文件列表信息。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • 版本库: 工作区有一个隐藏目录 .git ,这个不算工作区,保存项目的元数据和对象数据库,用来跟踪管理仓库。
  • 本地仓库: 本地仓库保存了对象被提交过的各个版本。git commit 后同步index的目录树到本地仓库,方便从下一步通过 git push 同步本地仓库与远程仓库。说明如下:
    • 只有把修改提交到本地仓库,该修改才能在仓库中留下痕迹
    • 可以在任何地方新建本地仓库,只需要在目标目录下执行 git init 指令,就会将此目录自动初始化为本地仓库,同时它会新建 .git 目录

工作区、版本库中的暂存区和版本库之间的关系:

image-20221218210558964

  • “HEAD” 实际是指向 master 分支的一个"游标"。
  • objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,其包含了创建的各种对象及内容。
  • 当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中
  • 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。 实现master和暂存区的联系
  • 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
  • 当执行 git rm --cached 命令时,会直接从暂存区删除文件,工作区则不做出改变。
  • 当执行 git checkout . 或者 git checkout – 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。
  • 当执行 git checkout HEAD . 或者 git checkout HEAD 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

二、Git的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# git的配置列表
git config --list

# 前提:在仓库中进行
# 编辑 git 配置文件:
git config -e # 针对当前仓库
git config -e --global # 针对系统上所有仓库

# 设置提交代码时的用户信息:
git config --global user.name "runoob"
git config --global user.email test@runoob.com

# 如果去掉 --global 参数只对当前仓库有效
1
2
3
4
5
6
7
8
9
# Github配置:ssh方式
# 生成SSH key
ssh-keygen -t rsa -C '...@163.com'

# Github 左边选择 SSH and GPG keys,然后点击 New SSH key。
# title可以任意填,key为C:/Users/.../.ssh/id_rsa.pub中的内容。

# 为了验证是否成功,输入以下命令:
ssh -T git@github.com

三、创建仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用当前目录作为 Git 仓库,该命令执行完后会在当前目录生成一个 .git 目录。
# 当你执行 git init 的时候,默认情况下 Git 就会为你创建 master/main 分支。
git init

# 使用指定目录作为Git仓库
# 初始化后,会在 newrepo 目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录
git init newrepo

# 添加远程仓库
git remote add origin git@github.com:.../PytorchTutorial.git
# 本地仓库分支关联远程仓库分支(可选),注意在此之前要先git add / git commit
# 关联目的是如果在本地分支下操作: git pull , git push ,不需要指定在命令行指定远程的分支.
git branch –set-upstream-to=origin/master master

四、基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
git clone ***
# git pull会下载当前正在工作的分支对应的远端内容
# 并且在下载成功之后马上执行一个git merge命令,为新下载下来的远端内容创建一次merge commit。
git pull 下载远程代码并合并
# git pull origin master --allow-unrelated-histories
git add 添加文件到暂存区
git commit 将暂存区内容添加到仓库中
# 在 Linux 系统中,commit 信息使用单引号 ',Windows 系统,commit 信息使用双引号 "
git push 上传远程代码并合并


# ————————————————————————————————
# Git 的工作就是创建和保存你的项目的快照及与之后的快照进行对比。

# 提交与修改
git status 查看仓库当前的状态,显示有变更的文件
git diff 比较文件的不同,即暂存区和工作区的差异
git reset 回退版本
git rm 删除工作区文件
git mv 移动或重命名工作区文件
# 提交日志
git log 查看历史提交记录
git blame <file> 以列表形式查看指定文件的历史修改记录
# 远程操作
git remote 远程仓库操作
# git remote add coworkers_repo git@bitbucket.org:coworker/coworkers_repo.git
git fetch 从远程获取代码库
# git fetch命令从远端仓库中下载commits, files, refs到本地仓库中,
# 但是fetch命令并不强迫让远端的变更合# 并到你的仓库。
# Git会对本地内容与fetch下载的内容进行隔离
# 这就保证了fetch命令更新的远端变更不会对本地正在进行的开发工作产生任何影响

.git文件夹

  • 本地分支的refs保存在./.git/refs/heads/文件夹下
  • 远端分支的refs存储在./.git/refs/remotes/文件夹下(git branch -r查看远端分支 + git checkout)
  • objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,其包含了创建的各种对象及内容。

五、分支管理

几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。

使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。

Git 分支实际上是指向更改快照的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 列出本地分支,-r 列出远程分支
git branch
# 创建分支:当你执行 git init 的时候,默认情况下 Git 就会为你创建 master 分支。
git branch (branchname)

# 切换分支
git checkout (branchname)
# git checkout -b (branchname) 命令来创建新分支并立即切换到该分支下,从而在该分支中操作

# 删除分支命令
git branch -d (branchname)

# 分支合并:可以使用以下命令将任何分支合并到当前分支中去:
git merge
# 合并完后就可以删除分支
git branch -d newtest

# 合并冲突

查看提交历史

Git 提交历史一般常用两个命令:

  • git log - 查看历史提交记录。
  • git blame - 以列表形式查看指定文件的历史修改记录。
1
2
3
4
5
6
7
# 使用 git log 命令列出历史提交记录

# 可以用 --oneline 选项来查看历史记录的简洁的版本
git log --oneline

# 可以用 --graph 选项,查看历史中什么时候出现了分支、合并。
# 可以用 --reverse 参数来逆向显示所有日志

为什么会发生合并冲突?

提示:以两个分支为例

  • git找到两个分支的ancestor commit,在当前情况下,ancestor commit为两个分支的分叉口。
  • 记录两分支在ancestor commit之后的修改记录(文本文件记录起始行号和修改范围)。
  • 最后生成合并结果,有三种情况:
    • 只有一条分支进行了修改,此时判断没有发生冲突;
    • 两条分支都进行了修改,但是修改记录没有发生重叠,则没有发生冲突;
    • 两条分支都进行了修改,并且修改记录发生了重叠,则发生了冲突。

理解git diff命令

git diff 用来比较文件之间的不同,其基本用法如下。

  • git diff:显示工作目录(working tree)与索引区(即暂存区快照,index,就是git add过的)之间的文件变更,即显示未被add的文件变更。

  • git diff --cached 或 git diff --staged:显示索引区和最后一次commit(HEAD)之间的文件更改,即显示已add但还未commit的文件变更。也即用"git commit"(不带-a)将被提交的文件变更。

  • git diff HEAD:显示工作目录与最后一次commit之间的文件变更,即显示所有未commit(包括未add和add两类)的文件变更。也即用"git commit -a”将被提交的文件变更。

  • git diff <分支名1> <分支名2> :比较两个分支上最后 commit 的内容的差别。以分支1为基础进行比较的。