Git

1. Git是什么?

Git 是一个分布式版本控制系统。 它的主要作用是跟踪和管理文件(尤其是代码文件)的变化

通过一个比喻来理解

假设你在用 Word 写一篇很重要的论文:

  1. 初稿:你写完了第一部分,保存为 论文_v1.docx

  2. 修改:你做了大量修改,但又怕改坏了,于是另存为 论文_v2.docx

  3. 导师反馈:导师给了意见,你在新文件上修改,又存为 论文_导师修改版.docx

  4. 自己再改:你自己又有新想法,于是又复制一份 论文_最终版.docx,然后继续改…

  5. 混乱:很快,你的文件夹里全是 最终版_v2_真的最终了_最新.docx 这样的文件,你根本分不清哪个是哪个,也不知道每个文件具体改了什么地方。

而 Git 就是为了解决这种混乱而生的!

使用 Git,你只需要一个项目文件夹。Git 会在背后为你记录每一次的修改(谁、在什么时候、为什么、修改了什么内容)。你可以随时回到任何一个历史版本,可以比较不同版本之间的差异,也可以创建不同的分支来尝试新功能而不影响主线。

2. 安装Git

2.1 Linux-centos

sudo yum -y install git

查看 Git 安装的版本

git --version

2.2 Linux-ubuntu

sudo apt-get -y install git

查看 Git 安装的版本

git --version

3. Git基本操作

3.1 创建 Git 本地仓库

本地仓库: 本质就是你的项目文件夹,但是这个文件夹被 Git 接管了,里面隐藏着一个 .git 目录,这里存储着 Git 的管理信息。

git init

3.2 配置 Git 仓库

当初始化 Git 后⾸先要做的事情是设置你的 ⽤⼾名称e-mail 地址。

3.2.1 配置命令
git config [--global] user.name "Your Name"
git config [--global] user.email "email@example.com"

其中 --global 是⼀个可选项。如果使⽤了该选项,表⽰这台机器上所有的 Git 仓库都会使⽤这个配置。如果你希望在不同仓库中使⽤不同的 name 或 e-mail ,可以省略 --global 选项,但要注意的是,执⾏命令时必须要在仓库⾥。

3.2.2 查看配置命令
git config -l
3.2.3 删除对应的配置命令
git config [--global] --unset user.name
git config [--global] --unset user.email

3.3 认识工作区、暂存区、版本库

3.3.1 概念
  • 工作区: 就是你当前初始化的 git 仓库(目录),你在这里新建、编辑、删除文件。所有你对代码的改动,首先都发生在这里。

    • 注意: 工作区中的文件还没有被 git 管理。
  • 暂存区: 英⽂叫 stage 或 index。⼀般存放在 .git ⽬录下的 index ⽂件(.git/index)中,我们把暂存区有时也叫作索引(index)。

    • 为什么需要暂存区? 这是 Git 设计非常精妙的地方。它让你可以精确控制哪些修改需要被提交。比如你同时修改了 A.txtB.txt,但这两个修改属于不同的功能,你可以只将 A.txt 的改动加入暂存区,先提交 A.txt 的功能,而 B.txt 的改动留待下次再提交。这保证了每次提交的原子性和清晰性。
  • 版本库: 就是隐藏在你项目目录下的 .git 文件夹,这个版本库⾥⾯的所有⽂件都可以被 Git 管理起来,每个⽂件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以还原。

在这里插入图片描述

  • 在创建 Git 版本库时,Git 会为我们⾃动创建⼀个唯⼀的 master 分⽀,以及指向 master 的⼀个指针叫 HEAD
3.3.2 工作区 -> 暂存区

1️⃣:将 filename 文件的修改(新增、修改、删除)添加到暂存区。

git add filename

2️⃣:将工作区所有的修改(新增、修改、删除)都添加到暂存区。

git add .
3.3.3 暂存区 -> 版本库
git commit -m "Submit Description information"

3.4 查看提交历史

当你使用 git commit 将更改保存到版本库后,每次提交都会形成一条历史记录。git log 就是用来展示这个历史记录的列表,它按照时间从近到远排列(最新的提交在最上面)。

git log 后分解一下没部分的信息:

  • commit id:提交的唯一标识符 (git reset时需要指定版本的操作中会用到此ID)。

  • Author:显示这次提交的作者姓名和邮箱。这来自于你安装 Git 时设置的 user.nameuser.email

  • Date:提交的时间。

  • git commit 时的描述信息。

1️⃣ :正常打印

git log

2️⃣ :简化输出

git log --oneline

3️⃣:图形化显示分支和合并

git log --oneline --graph

4️⃣:不仅显示提交信息,还显示每次提交所引入的具体代码差异

git log -p

5️⃣:只显示最近 n 条提交

git log -n

6️⃣:显示指定时间之后/之前的提交

git log --since = "yyyy-mm-dd"
git log --until = "yyyy-mm-dd"

3.5 显示工作区和暂存区的当前状态

在你执行 git addgit commit 之前,你应该先运行 git status 来确认一下当前的情况,避免误操作。

git status

3.6 版本回退

3.6.1 git reset
git reset [--soft | --mixed | --hard] [HEAD]
  • --mixed 为默认选项,使⽤时可以不⽤带该参数。重置暂存区,但不触碰工作区。你之前的修改会保留在工作目录,但变回了add 的状态

  • --soft 不触碰工作区和暂存区。你之前的修改仍然处于 add的状态 。

  • --hard 工作区和暂存区都彻底回退。

  • HEAD 说明:

    • 可直接写成 commit id,表⽰指定退回的版本

    • HEAD 表⽰当前版本

    • HEAD^ 上⼀个版本

    • HEAD^^ 上上⼀个版本

    • 以此类推…

    • 可以使⽤ 〜数字表⽰:

    • HEAD~0 表⽰当前版本

    • HEAD~1 上⼀个版本

    • HEAD~2 上上⼀个版本

    • 以此类推…

工作区 暂存区 版本库 对应的操作
当前状态 hello git
hello world
hello git
hello world
hello git
hello world
–soft hello git
hello world
hello git
hello world
hello git git commit
–mixed hello git
hello world
hello git hello git git add
git commit
–hard hello git hello git hello git 连工作区的内容也要重新开始写

测试回退功能,我们先做⼀些准备⼯作:更新3个版本的 ReadMe,并分别进⾏3次提交,如下所⽰:

# 第⼀次修改提交
ccc@ccc:~/gitcode$ cat ReadMe
hello version1
hyb@139-159-150-152:~/gitcode$ git add ReadMe
hyb@139-159-150-152:~/gitcode$ git commit -m "add version1"
[master cff9d1e] add version1
1 file changed, 1 insertion(+)

# 第⼆次修改提交
ccc@ccc:~/gitcode$ cat ReadMe
hello version1
hello version2
hyb@139-159-150-152:~/gitcode$ git add ReadMe
hyb@139-159-150-152:~/gitcode$ git commit -m "add version2"
1 file changed, 1 insertion(+)

# 第三次修改提交
ccc@ccc:~/gitcode$ cat ReadMe
hello version1
hello version2
hello version3
hyb@139-159-150-152:~/gitcode$ git add ReadMe
hyb@139-159-150-152:~/gitcode$ git commit -m "add version3"
[master d95c13f] add version3
1 file changed, 1 insertion(+)

# 查看历史提交记录
hyb@139-159-150-152:~/gitcode$ git log --pretty=oneline
d95c13ffc878a55a25a3d04e22abfc7d2e3e1383 (HEAD -> master) add version3
14c12c32464d6ead7159f5c24e786ce450c899dd add version2
cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1

现在,如果我们在提交完 version3 后, 发现 version 3 编写错误,想回退到 version2,重新基于 version 2 开编写。由于我们在这⾥希望的是将⼯作区的内容也回退到 version 2 版本,所以需要⽤到 --hard 参数,⽰例如下:

ccc@ccc:~/gitcode$ git log --pretty=oneline
d95c13ffc878a55a25a3d04e22abfc7d2e3e1383 (HEAD -> master) add version3
14c12c32464d6ead7159f5c24e786ce450c899dd add version2
cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
...

ccc@ccc:~/gitcode$ git reset --hard 14c12c32464d6ead7159f5c24e786ce4
HEAD is now at 14c12c3 add version2
ccc@ccc:~/gitcode$ cat ReadMe
hello version1
hello version2
3.6.2 git reflog

但如果我现在后悔了,再想回到 version3 怎么办?别慌,Git 几乎记录了你的所有操作。使用 git reflog 命令,你会看到所有 HEAD 移动的记录。

ccc@ccc:~/gitcode$ git reflog
14c12c3 (HEAD -> master) HEAD@{0}: reset: moving to 14c12c32464d6ead7159f5c24e78
d95c13f HEAD@{1}: commit: add version3
14c12c3 (HEAD -> master) HEAD@{2}: commit: add version2
cff9d1e HEAD@{3}: commit: add version1

# 回退到v3
ccc@ccc:~/gitcode$ git reset --hard d95c13f
HEAD is now at d95c13f add version3

# 查看⼯作区
ccc@ccc:~/gitcode$ cat ReadMe
hello version1
hello version2
hello version3

3.7 撤销修改

3.7.1 情况一:对于工作区的代码,还没有add
git checkout -- filename
3.7.2 情况二:已经add,但是没有commit

1️⃣

git reset HEAD filename
git checkout -- filename

2️⃣

git reset --hard HEAD
3.7.3 情况三:已经add,并且也commit

注意:前提是没有 git push

git reset --hard HEAD^
工作区 暂存区 版本库 解决方式
xxx code git checkout – filename
xxx code xxx code git reset --hard HEAD
xxx code xxx code xxx code git rese --hard HEAD^

解决后:

工作区 暂存区 版本库

核心规则:

  • HEAD 是一个指针,指向你当前所在的提交。

  • 当你 commit 后,HEAD 会带着分支指针一起移动到新的提交。所以你想回退,就需要用 HEAD^HEAD~n 来指向之前的提交。

  • 当你没有 commit 时,HEAD 纹丝不动,依然指向上一次提交。所以你的所有撤销操作都是对照 HEAD 来进行。

简单的口诀:只要 git commit 了 就一定要 HEAD^ 如果没有 commit 就是 HEAD。

4. 分支管理

4.1 理解HEAD

本质是一个指针,可以指向其他分支,被指向的分支就是当前正在工作的分支所在的提交

可以把 HEAD 想象成游戏中的存档点。附加状态就像你在主线任务上不断创建新存档;创建分支就像你从当前的游戏的存档点去探索一些新的内容,但是此时你的主线任务还是旧的,所以需要将你在新分支探索的新内容添加到主线任务中。

.git
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── index # 暂存区
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
│  #(每一次对文件内容的新修改,在通过 git add 添加到暂存区后,Git 都会为其生成一个数据对象(blob object)。而执行 git commit时,    │Git 会生成一个提交对象(commit object)来封装这次提交。
├── objects 
│   ├── 03
│   │   └── 850187d483fa3a8828f695ea2d1b9d7f9f22d3
│   ├── 05
│   │   ├── 7e450bd946bb6f72576b9beacc3538f5ac5a4f
│   ├── info
│   └── pack
├── ORIG_HEAD
└── refs
    ├── heads
    │   └── master 
    └── tags

# 通过 cat 查看 HEAD
cat .git/HEAD
ref: refs/heads/master

4.2 查看分支

查看本地分支:

git branch

查看本地和远程分支:

git branch -a

4.3 创建分支

git branch branch-name

在这里插入图片描述


4.4 切换分支

git checkout branch-name

在这里插入图片描述


在 dev 分支上进行 commit 操作

在这里插入图片描述


4.5 合并分支

前提: 需要切换回 master 分支。

git checkout master
git merge dev        #dev分支中的内容合并到master分支上

在这里插入图片描述


当前属于快速合并模式 ,直接切换,没有遇到合并冲突。

4.6 删除分支

git branch -d branch-name

注意:你不能在 dev 分支上删除它自己,必须先切换到其他分支才能执行删除 dev 分支的操作。

4.7 创建并切换分支

git checkout -b brance-name

4.8 合并冲突

手动合并冲突时,可以选择保留dev分支的内容,也可以选择保留master分支的内容,或者都保留。

手动合并冲突后,需要 git addgit commit

在这里插入图片描述


4.9 禁用快速合并模式

dev 分支的更改合并到当前分支,并且强制创建一个新的提交记录来明确标记这次合并行为

git merge --no-ff -m "merge dev" dev 
  • fast-forward (快进合并):如果主分支(例如 master)自新分支(dev)创建以来没有新的提交,Git 默认会简单地移动指针来完成合并,不会创建新的提交。这使得历史记录呈一条直线,但丢失了曾经存在过一个分支并进行合并的信息

假设你的提交历史一开始是这样的:

        A---B---C dev 
        / 
...---D---E  master (HEAD)

如果不加 --no-ff (默认快速合并):

如果 master 分支在创建 dev 后没有新提交,合并后历史会变成一条直线:

...---D---E---A---B---C  master (HEAD), dev

使用 --no-ff 后:

          A---B---C  dev
         /         \
...---D---E---------M  master (HEAD)

这个 M 提交就是 -m "merge dev" 所创建的那个合并提交。

4.10 一种特殊情况修改bug分支

假如我们现在正在 dev 分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有 bug,需要解决。在Git中,每个 bug 都可以通过⼀个新的临时分⽀来修复,修复后,合并分⽀,然后将临时分⽀删除。可现在 dev2 的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?

ccc@ccc:~/gitcode$ git branch    # 查看分支情况
* dev
master
ccc@ccc:~/gitcode$ cat ReadMe    # 查看 ReadMe 文件
hello world
i am coing ...    # 在 dev 分支上对 ReadMe 文件新增的内容
...


ccc@ccc:~/gitcode$ git checkout master    # dev 分支切换到 master 分支
ccc@ccc:~/gitcode$ git branch    # 查看分支情况
dev
* master

ccc@ccc:~/gitcode$ cat ReadMe    # 查看 ReadMe 文件
hello world
i am coding ...    # 这里发现由于 dev 分支开发新内容没有提交,导致 master分支中的 ReadMe 文件也存在 i am coding ...
...

# 我们的期望是 master 分支没有在 dev 分支的工作区新增的但是没有提交的内容
# 可以通过 git stash 将当前 dev 分支中工作区的内容进行存储,被存储的内容额可以在将来某个时间恢复出来


ccc@ccc:~/gitcode$ git checkout dev    # master 分支切换到 dev 分支
ccc@ccc:~/gitcode$ git branch          # 查看分支情况
* dev
master
ccc@ccc:~/gitcode$ git stash           # 将 dev 分支中工作区的内容进行存储
ccc@ccc:~/gitcode$ cat ReadMe          # 查看 ReadMe 文件
hello world
...

ccc@ccc:~/gitcode$ git checkout master    # dev 分支切换到 master 分支
ccc@ccc:~/gitcode$ git branch             # 查看分支情况
dev
* master
ccc@ccc:~/gitcode$ cat ReadMe             # 查看 ReadMe 文件
hello world
...

# 现在就可以放心的新建 fix_bug 分支来处理 master 的 bug
ccc@ccc:~/gitcode$ git checkout -b fix_bug    # 新建 fix_bug 分支并切换
ccc@ccc:~/gitcode$ git branch                 # 查看分支情况
dev
master
* fix_bug
# 比如将 ReadMe 文件中的 hello world 改为 hello world world
ccc@ccc:~/gitcode$ cat ReadMe          # 查看 ReadMe 文件
hello world world
...
ccc@ccc:~/gitcode$ git add ./ReadMe                
ccc@ccc:~/gitcode$ git commit -m "fix master bug"


ccc@ccc:~/gitcode$ git checkout master    # 将 fix_bug 分支切换回 master 分支
ccc@ccc:~/gitcode$ git branch             # 查看分支情况
dev
* master
fix_bug
ccc@ccc:~/gitcode$ git merge --no-ff -m "fix bug" fix_bug # 使用非快速合并模式合并 fix_bug 分支
ccc@ccc:~/gitcode$ cat ReadMe               # 查看 ReadMe 文件
hello world world
...
ccc@ccc:~/gitcode$ git branch -d fix_bug    #删除 fix_bug 分支
ccc@ccc:~/gitcode$ git branch               # 查看分支情况
dev
* master

ccc@ccc:~/gitcode$ git checkout dev         # 将 master 分支切换到 dev 分支继续开发没有提交的内容
ccc@ccc:~/gitcode$ git stash pop            # 恢复之前 dev 存储工作区的内容
# 你可以多次stash,恢复的时候,先⽤ git stash list 查看,然后恢复指定的stash,⽤命令 git stash apply stash@{0}
ccc@ccc:~/gitcode$ cat ReadMe               # 查看 ReadMe 文件
hello world
i am coding
...
ccc@ccc:~/gitcode$ git add ./ReadMe                
ccc@ccc:~/gitcode$ git commit -m "i am coding done!"

# 但是此时,修复 bug 的内容,并没有在 dev 分支上显示
# 此时,我们可以切换回 master 分支中合并 dev 分支,但是当复杂性高的时候,难免会出错。
# 所以,建议是将 master的内容合并到 dev 分支上,等测试/调试完毕后再将 dev 分支的内容合并回 master 分支
ccc@ccc:~/gitcode$ git merge --no-ff -m "master merge dev - test" master  # master 分支合并到 dev 分支上
# 处理冲突
ccc@ccc:~/gitcode$ git checkout master  # dev 切换到 master 分支,已经在 dev 中处理完毕冲突,直接将 dev 与 master 合并
ccc@ccc:~/gitcode$ git merge --no-ff -m "dev merge master - test end" dev # dev 合并至 master

ccc@ccc:~/gitcode$ git branch -d dev    # 删除 dev 分支
ccc@ccc:~/gitcode$ git branch           # 查看当前分支情况
* master

4.11 强制删除分支

git branch -D branch-name

5. 远程操作

5.1 远程仓库

你可以把远程仓库想象成一个部署在中央服务器上的项目中心库(比如 GitHub, Gitee)。而你自己电脑上的 Git 仓库,则是这个中心库的一个完整副本

为什么要使用远程仓库?

  • 协作:这是最主要的目的。它让多个开发者可以共享代码,并在同一个项目上并行工作。

  • 备份:将代码推送到远程仓库,相当于为你的项目做了一个可靠的云端备份,防止本地电脑损坏导致代码丢失。

5.2 克隆远程仓库

git clone url

5.3 向远程仓库推送

向远程仓库推送的本质就是:用你本地仓库的最新代码,去更新远程仓库中相对较旧的代码。

git push <远程主机名> <本地分支名>:<远程分支名>
git push origin master:master
# 如果当前本地分支名和远程分支名一致 可以省略
git push origin master

5.4 拉取远程仓库

拉取远程仓库的本质是:用远程仓库的最新代码,来更新你本地相对较旧的代码。

git pull <远程主机名> <远程分⽀名>:<本地分⽀名>
#如果当前本地分支名和远程分支名一致 可以省略
git pull <远程主机名> <远程分⽀名>
git pull origin master

注意:git pull 是拉取 + 合并。

5.5 .gitignore

在⽇常开发中,我们有些⽂件不想或者不应该提交到远端。在 Git ⼯作区的根⽬录下创建⼀个特殊的 .gitignore ⽂件,然后把要忽略的⽂件名填进去,Git 就会⾃动忽略这些⽂件了。

# 可以直接写文件名或者文件后缀
*.so
*.ini
# 排除所有的.so文件,但是b.so可以提交
!b.so

强制被忽略的文件进行 add 操作。

git add -f a.so

5.6 创建本地分支并切换,同时与远程分支建立连接

git checkout -b dev origin/dev
  • 已建立连接后的日常推送git push

  • 已建立连接后的日常拉取git pull

  • 查看已建立的连接git branch -vv

5.7 创建本地分支后并切换,之后与远程分支建立连接

git checkout -b dev
git branch --set-upstream-to=origin/dev dev

5.8 远程分支删除后,本地 git branch -a 依然能看到远程被删除的分支的解决办法

git remote prune origin
# 再查看就是正常的了
git branch -a
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐