Git从原理到实践的全面指南 | 实战篇

495 阅读24分钟

Git是一个非常强大的代码管理工具,它不仅可以让你方便地提交、推送、拉取代码,还可以让你灵活地处理各种复杂的分支、合并、冲突等问题。说到使用,相信大家都会,无非就是commit、push、pull 。但是如果要说熟练掌握Git的使用,对代码管理做到得心应手却不是那么容易。现在我们就先从基本的概念开始,系统地学习Git的原理和操作。

👉 概念篇

基本使用

image-20230624131410755

创建新仓库

# 本地初始化git
git init

# 关联远程仓库
git remote add <shortname> <url>

检出/克隆仓库

# 克隆远程仓库,并且直接使用仓库名作为文件夹名称
git clone <仓库地址>

# 克隆,并且自定义本地文件夹名称
git clone <仓库地址> "文件名"

添加和提交

将文档添加到暂存区

# 添加指定文件
git add <filename>
# 或直接使用*号添加全部
git add *

将暂存区内容提交

# -m表示message
git commit -m "代码提交信息"

# -a表示all
git commit  -am "代码提交信息"

-am是两个选项的组合,-a表示all,-m表示message。

  • -a选项可以让git commit自动把已经跟踪过的文件(即修改或删除的文件)添加到暂存区,而不需要先用git add命令。
  • -m选项可以让你直接在命令行中输入提交信息,而不需要打开文本编辑器。

例如,git commit -am “修改了a.txt” 就会把修改过的a.txt文件添加到暂存区,并且创建一个带有修改了a.txt信息的提交。

推送代码

# 把 master 换成你想要推送的任何分支
git push origin master

# 指定分支
git push -u origin master

-u是一个选项,表示set-upstream,也就是设置上游分支。 使用-u选项可以让本地分支和远程分支建立关联,这样在以后的推送或拉取操作中就不需要指定分支名了。

如果你的本地分支和远程分支有关联(upstream),那么你可以直接用git push命令,不用再写远程仓库和分支的名字。 例如,如果你的本地分支foo关联了远程仓库origin的foo分支,那么你可以直接用git push来推送本地foo分支到远程foo分支,而不用写git push origin foo

如果你的本地分支没有关联远程分支,那么你就需要指定分支名,或者使用-u选项来建立关联。 例如,如果你有一个新的本地分支bar,你想推送到远程仓库origin的bar分支,那么你可以用git push origin bar或者git push -u origin bar来推送, 并且后者会让这两个分支关联起来。

分支处理

# 创建分支
git branch  <分支名称>

# 切换分支
git checkout 分支名称

# 命令合并(创建并切换到新的分支)
git checkout -b 分支名称

# 删除指定分支
git branch -d 分支名称

# 强制删除指定分支(没有被合并到 mas -d 改成 -Dter 过的 branch 在删除时会失败,如果确认要删除这个分支,则可以可以把 -d 改成 -D,即把小写换成大写)
git branch -D 分支名称

# 使用该分支推送
git push origin <分支名称>

# 拉取远程分支
git fetch <remote>


# 查看分支列表
git branch

# 查看每一个分支的最后一次提交
git branch -v

# 查看哪些分支已经合并到当前分支
git branch --merged

# 查看所有包含未合并工作的分支
git branch --no-merged

更新合并

# 拉取远程代码
git pull

# 合并指定分支
git merge <branch>

# 预览分支差异
git diff <source_branch> <target_branch>

其他命令

# 查看所有分支
git branch -a 

# 查看当前配置有哪些远程仓库及其地址
git remote -v  

# 查看文件处于什么状态
git status

进阶用法

image-20230624133356898

add

add 指令除了 git add 文件名 这种用法外,还可以使用 add . 来直接把工作目录下的所有改动全部放进暂存区

# 所有改动全部放进暂存区
git add .

# 查看暂存状态
git status

通过 add 添加进暂存区的不是文件名,而是具体的文件改动内容。

push

push 是把当前的分支上传到远程仓库,并把这个 branch 的路径上的所有 commit也一并上传。

push 的时候,如果当前分支是一个本地创建的分支,需要指定远程仓库名和分支名,用 git push origin branch_name 的格式,而不能只用 git push;或者可以通过 git config 修改 push.default 来改变 push 时的行为逻辑。

push 的时候之后上传当前分支,并不会上传 HEAD;远程仓库的 HEAD 是永远指向默认分支(即 master)的。

merge

merge 的意思是「合并」,它做的事也是合并:指定一个 commit,把它合并到当前的 commit 来。具体来讲,merge 做的事是:

从目标 commit 和当前 commit (即 HEAD 所指向的 commit)分叉的位置起,把目标 commit 的路径上的所有 commit 的内容一并应用到当前 commit,然后自动生成一个新的 commit

示例:把branch1合并到master

image-20230612154514252

HEAD 指向了 master,所以如果这时执行:

git merge branch1

Git 会把 56 这两个 commit 的内容一并应用到 4 上,然后生成一个新的提交

适用场景

merge 最常用的场景有两处:

  • 合并分支

当一个 branch 的开发已经完成,需要把内容合并回去时,用 merge 来进行合并。

  • pull 的内部操作

pull 的实际操作其实是把远端仓库的内容用 fetch 取下来之后,用 merge 来合并。

冲突问题

当前分支和目标分支在使用merge 合并的时候,有一定的自动合并能力

1)修改不同的文件

如果一个分支改了 A 文件,另一个分支改了 B 文件,那么合并后就是既改 A 也改 B。这个动作会自动完成;

2)修改通一个文件,不同地方

如果两个分支都改了同一个文件,但一个改的是第 1 行,另一个改的是第 2 行,那么合并后就是第 1 行和第 2 行都改,也是自动完成。

3)修改同一个文件,同一个地方(冲突)

这种情况 Git 称之为:冲突(Conflict)。这个时候git不会自动合并,但是会把它们放在一起,由你来决定。

解决冲突

比如:

<<<<<<<< HEAD
文件1的内容
==========
文件2的内容
<<<<<<<<< dev  

假设你决定保留 HEAD 的修改,那么只要删除掉 dev 分支的修改,再把 Git 添加的那三行 <<< === >>> 辅助文字也删掉,保存文件退出,「解决掉冲突」就完成了。

放弃解决冲突

当Git 仓库处于冲突待解决的中间状态,所以如果你最终决定放弃这次 merge,则需要执行一次 merge --abort 来手动取消它:

# 输入这行代码, Git 仓库就会回到 merge 前的状态
git merge --abort

rebase

rebase 的意思是,给你的 commit 序列重新设置基础点(也就是父 commit)。

展开来说就是,把你指定的 commit 以及它所在的 commit 串,以指定的目标 commit 为基础,依次重新提交一次。

有些人不喜欢 merge,因为在 merge 之后,commit 历史就会出现分叉,这种分叉再汇合的结构会让有些人觉得混乱而难以管理。如果你不希望 commit 历史出现分叉,可以用 rebase 来代替 merge

和merge的区别

rebase 是在需要被 rebasecommit 上进行操作

使用rebase的一个常见场景是,当你在一个本地分支上开发新功能时,你想要把远程仓库中的最新更新合并到你的分支上,但是你又想保持你的分支历史简洁,好像你是在最新的基础上开发的一样。这样做的好处是,当你把你的分支合并回主分支时,可以避免一些不必要的合并冲突,也可以让你的提交历史更清晰,更容易追踪和调试。

示例

例如,假设你有一个名为dev的本地分支,你在上面开发了一些新功能。同时,远程仓库中的主分支(origin/master)也有了一些更新。你想要把这些更新合并到你的dev分支上,但是你不想用merge命令,因为那样会产生一个多余的合并提交。你可以用rebase命令来实现这个目的:

git checkout dev
git rebase origin/master

git checkout master
git merge dev

这样做会把你dev分支上相对于origin/master分支的提交重新应用到origin/master分支上,让你的dev分支看起来像是从origin/master分支最新的提交开始创建的。然后,当你想要把dev分支合并回主分支时,只需要用git merge dev命令就可以完成一个快进合并(fast-forward merge),而不会产生任何冲突或多余的提交。

image-20230624140017079

通过 rebase,把ABC这条 commit的基础点从 D 换成了 F。通过这样的方式,就让本来分叉了的提交历史重新回到了一条线。这种「重新设置基础点」的操作,就是 rebase 的含义。

为什么要切换到 devrebase,然后再切回 mastermerge ,而不是直接在 master 上执行 rebase

主要是为了避免和远端仓库发生冲突,rebase 后的 commit 虽然内容rebase 之前相同,但它们已经是不同的 commits 了。如果直接从 master 执行 rebase 的话。这就导致 master 上之前的两个最新 commit 被剔除了。如果这两个 commit 之前已经在中央仓库存在,这就会导致没法 push 了。

reset

reset 用来重置 HEAD 以及它所指向的 branch 的位置。

reset --hard HEAD^ 之所以起到了撤销 commit 的效果,是因为它把 HEAD 和它所指向的 branch 一起移动到了当前 commit 的父 commit 上,从而起到了「撤销」的效果。

Git 的历史只能往回看,不能向未来看,所以把 HEADbranch 往回移动,就能起到撤回 commit 的效果。

无参数:保留工作目录,并清空暂存区

reset 如果不加参数,那么默认使用 --mixed 参数。它的行为是:保留工作目录,并且清空暂存区。

也就是说,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。简而言之,就是「把所有差异都混合(mixed)放在工作目录中」。

--hard:重置工作目录

reset --hard 会在重置 HEADbranch 的同时,重置工作目录里的内容。

当你在 reset 后面加了 --hard 参数时,你的工作目录里的内容会被完全重置为和 HEAD 的新位置相同的内容。换句话说,就是你的未提交的修改会被全部擦掉。

reset --hard不仅可以撤销提交,还可以用来把 HEADbranch 移动到其他的任何地方。

git reset --hard branch2

--soft:保留工作目录

reset --soft 会在重置 HEADbranch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。

问题处理

git reset恢复指定版本代码后,再无法提交到远程库;git status提示出现2个分支不同提交

错误提示:Your branch and 'origin/master' have diverged, and have 1 and 1 different commits each, respectively

# 从远程仓库拉取更新,并且用rebase的方式合并到当前分支上等同于( git fetch + git rebase origin/master)
git pull --rebase origin master

# 把内容提交到远程仓库
git push origin master

checkout

可以使用checkout来切换分支

git checkout 分支名称

checkout 并不止可以切换 branchcheckout 本质上的功能其实是:签出( checkout )指定的 commit

git checkout 分支名称 的本质,其实是把 HEAD 指向指定的 branch,然后签出这个 branch 所对应的 commit 的工作目录。

所以同样的,checkout 的目标也可以不是 branch,而直接指定某个 commit

git checkout HEAD^^
git checkout master~5
git checkout 78a4bc
git checkout 78a4bc^

checkout 和 reset

相同点:checkoutreset 都可以切换 HEAD 的位置。

不同点:reset 在移动 HEAD 时会带着它所指向的 branch 一起移动,而 checkout 不会。当你用 checkout 指向其他地方的时候,HEAD 和 它所指向的 branch 就自动脱离了。

checkout 有一个专门用来只让 HEADbranch 脱离而不移动 HEAD 的用法

# 执行这行代码,Git 就会把 HEAD 和 branch 脱离,直接指向当前 commit
git checkout --detach

restore

取消暂存

 git restore --staged <已被暂存的文件名>

撤销对文件的修改,将它还原成上次提交时的样子

 git restore <文件名>

请务必记得这是一个危险的命令。 你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。 除非你确实清楚不想要对那个文件的本地修改了,否则请不要使用这个命令。

stash

临时存放工作目录的改动。

在 Git 中,stash 指令可以帮你把工作目录的内容全部放在你本地的一个独立的地方,它不会被提交,也不会被删除,你把东西放起来之后就可以去做你的临时工作了,做完以后再来取走,就可以继续之前手头的事了。

具体说来,stash 的用法很简单。当你手头有一件临时工作要做,需要把工作目录暂时清理干净,那么你可以

git stash

这个时候你的工作目录的改动就被清空了,所有改动都被存了起来。然后你就可以从你当前的工作分支切到其他分支,等重新切回这个分支之后,操作:

# 之前存储的东西就都回来了
git stash pop

注意:没有被 track 的文件(即从来没有被 add 过的文件不会被 stash 起来,因为 Git 会忽略它们。如果想把这些文件也一起 stash,可以加上 -u 参数,它是 --include-untracked 的简写。就像这样:

git stash -u

reflog

这个指令可以处理分支被误删想恢复的问题。

reflog 是 "reference log" 的缩写,使用它可以查看 Git 仓库中的引用的移动记录。如果不指定引用,它会显示 HEAD 的移动记录。

假如你误删了 dev 这个分支,那么你可以查看一下 HEAD 的移动历史:

git reflog

image-20230613164910998

从图中可以看出,HEAD 的最后一次移动行为是「从 dev 移动到 master」。而在这之后,dev 就被删除了。所以它之前的那个 commit 就是 dev 被删除之前的位置了,也就是第二行的 6b8a52a

# 切换回 6b8a52a,然后重新创建 dev。这样刚删除的 dev 分支就找回来了
git checkout 6b8a52a
git checkout -b dev

注意:不再被引用直接或间接指向的 commit 会在一定时间后被 Git 回收,所以使用 reflog 来找回删除的 branch 的操作一定要及时,不然有可能会由于 commit 被回收而再也找不回来。

查看其他引用的reflog

reflog 默认查看 HEAD 的移动历史,除此之外,也可以手动加上名称来查看其他引用的移动历史,例如:

git reflog master

进阶用法

修正commit / amend

修正最新commit

有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。

可以修改之后,在提交一个 commit,不过还有一个更加优雅和简单的解决方法:可以运行带有 --amend 选项的提交命令来重新提交

commit --amend 做的事就是它的字面意思:对最新一条 commit 进行修正。

"amend" 是「修正」的意思。在提交时,如果加上 --amend 参数,Git 不会在当前 commit 上增加 commit,而是会把当前 commit 里的内容和暂存区(stageing area)里的内容合并起来后创建一个新的 commit

与其说是修复旧提交,倒不如说是完全用一个 新的提交 替换旧的提交。从效果上来说,就像是旧有的提交从未存在过一样,它并不会出现在仓库的历史中。

修补提交最明显的价值是可以稍微改进你最后的提交,而不会让“啊,忘了添加一个文件”或者 “小修补,修正笔误”这种提交信息弄乱你的仓库历史。

修正其他commit

如果不是最新的 commit 写错,就不能用 commit --amend 来修复了,而是要用 rebase。不过需要给 rebase 也加一个参数:-i

rebase -irebase --interactive 的缩写形式,意为「交互式 rebase」

所谓「交互式 rebase」,就是在 rebase 的操作执行之前,你可以指定要 rebasecommit 链中的每一个 commit 是否需要进一步修改。

# 把当前 commit(HEAD 所指向的 commit) rebase 到 HEAD 之前 2 个的 commit 上
git rebase -i HEAD^^

# 在修复完成之后,就可以用 rebase --continue 来继续 rebase 过程,把后面的 commit 直接应用上去
git rebase --continue

说明:在 Git 中,有两个「偏移符号」: ^~

^ 的用法:在 commit 的后面加一个或多个 ^ 号,可以把 commit 往回偏移,偏移的数量是 ^ 的数量。例如:master^ 表示 master 指向的 commit 之前的那个 commitHEAD^^ 表示 HEAD 所指向的 commit 往前数两个 commit

~ 的用法:在 commit 的后面加上 ~ 号和一个数,可以把 commit 往回偏移,偏移的数量是 ~ 号后面的数。例如:HEAD~5 表示 HEAD 指向的 commit往前数 5 个 commit

丢弃commit

丢弃最新的commit

语法:git reset --hard 目标commit

例如:

# 撤销最新的提交
git reset --hard HEAD^

HEAD 表示 HEAD^ 往回数一个位置的 commit

你被撤销的那条提交并没有消失,只是你不再用到它了。如果你在撤销它之前记下了它的 SHA-1 码,那么你还可以通过 SHA-1 来找到他它。

丢弃其他commit

和上面的修正一样,可以使用rebase来处理。(在编辑界面中删除想撤销的 commit

比如,想撤销倒数第二条 commit

git rebase -i HEAD^^

# 可以查看log是否生效
git log

撤销提交

rebase 加上 --onto 选项之后,可以指定 rebase 的「起点」。

一般的 rebase,告诉 Git 的是「我要把当前 commit 以及它之前的 commits 重新提交到目标 commit 上去,这其中,rebase 的「起点」是自动判定的:选取当前 commit 和目标 commit 在历史上的交叉点作为起点。

# 在 rebase 命令中直接剔除想撤销的 commit
git  rebase --onto

--onto 参数后面有三个附加参数:目标 commit、起点 commit(注意:rebase 的时候会把起点排除在外)、终点 commit

示例

# 以倒数第二个 commit 为起点(起点不包含在 rebase 序列里),branch1 为终点,rebase 到倒数第三个 commit 上
git rebase --onto HEAD^^ HEAD^ branch1

修正已push的commit

  • 如果是自己使用的分支

    【解决方案】:把写错的 commit 修改或者删除掉,然后再 push 上去。

    git push origin  分支名称  -f
    

这个时候会出现预料中的冲突,希望用本地的内容覆盖掉中央仓库的内容。所以可以选择强行push(-f--force 的缩写,意为「忽略冲突,强制 push」)

如果是master或者是别人的分支,则一定不要强制push,否则会覆盖掉被人的提交。

  • 如果已合并到master

    【解决方案】:增加一个新的提交,把之前提交的内容抹掉。

    【例如】:你增加了一行代码,你希望撤销它,那么你就做一个删掉这行代码的提交;如果你删掉了一行代码,你希望撤销它,那么你就做一个把这行代码还原回来的提交。这个时候可以使用revert指令

    # 这行代码的意思是,增加一条新的 commit,它的内容和倒数第二个 commit 是相反的,从而和倒数第二个 commit 相互抵消,达到撤销的效果
    git revert HEAD^
    

revert 完成之后,把新的 commitpush 上去,这个 commit 的内容就被撤销了。

它和前面所介绍的撤销方式相比,最主要的区别是,这次改动只是被「反转」了,并没有在历史中消失掉,你的历史中会存在两条 commit :一个原始 commit ,一个对它的反转 commit

打标签

Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0v2.0 等等)。

列出标签

# 列出所以标签
git tag

# 列出1.8.5 系列标签
git tag -l "v1.8.5*"

创建标签

Git 支持两种标签

  • 轻量标签(lightweight)

    它很像一个不会改变的分支——它只是某个特定提交的引用。

    # git tag <标签名>
    git tag v1.4-temp
    
    # 查看标签信息
    git show v1.4-temp
    
  • 附注标签(annotated)

    附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。 通常会建议创建附注标签,这样你可以拥有以上所有信息。但是如果你只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。

    # 指定 -a 选项创建附注标签
    # -m 选项指定了一条将会存储在标签中的信息。 如果没有为附注标签指定一条信息,Git 会启动编辑器要求你输入信息。
    git tag -a v1.4 -m "my version 1.4"
    
    # 查看标签信息
    git show v1.4
    

后期打标签

要在那个提交上打标签,你需要在命令的末尾指定提交的校验和(或部分校验和)

git tag -a v1.2 9fceb02

共享标签

默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样——你可以运行 git push origin <tagname>

# 推送指定标签
git push origin v1.4

# 推送所有标签
 git push origin --tags

删除标签

删除掉本地仓库上的标签, git tag -d <tagname>

git tag -d  v1.4-temp

删除远程标签

 git push origin --delete <tagname>

检出标签

切换到指定标签,如果你做了某些更改然后提交它们,标签不会发生变化, 但你的新提交将不属于任何分支,并且将无法访问,除非通过确切的提交哈希才能访问。

git checkout v2.0.0

因此,如果你需要进行更改,比如你要修复旧版本中的错误,那么通常需要创建一个新分支

git checkout -b version2 v2.0.0

历史记录

查看历史记录

git log

# 列出最近两周的所有提交
git log --since=2.weeks

不传入任何参数的默认情况下,git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面。

这个命令会列出

  • 每个提交的 SHA-1 校验(commit)
  • 作者的名字和电子邮件地址(Author)
  • 提交时间以及提交说明。(Date)

查看详细历史

git log -p

# -2代表只显示最近的两次提交
git log -p -2

-p--patch 的缩写,通过 -p 参数,你可以看到每一个 commit 的每一行改动,很适合用于代码 review

查看简要统计

git log --stat

如果你只想大致看一下改动内容,但并不想深入每一行的细节(例如你想回顾一下自己是在哪个 commit 中修改了 games.txt 文件),那么可以把选项换成 --stat

--stat 选项会在每次提交的下面列出所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加了。 在每次提交的最后还有一个总结

格式化查看log

--pretty,使用其他格式显示历史提交信息。可用的选项包括 oneline、short、full、fuller 和 format(用来定义自己的格式)。

# 仅显示 SHA-1 校验和所有 40 个字符中的前几个字符。
git log --pretty=oneline

git log --pretty=format:"%h - %an, %ar : %s"

# `--graph`在日志旁以 ASCII 图形显示分支与合并历史。
 git log --pretty=format:"%h %s" --graph

image-20230622162914656

git log --pretty=format 常用的选项

  • %H:提交的完整哈希值
  • %h:提交的简写哈希值
  • %T:树的完整哈希值
  • %t:树的简写哈希值
  • %P:父提交的完整哈希值
  • %p:父提交的简写哈希值
  • %an:作者名字
  • %ae:作者的电子邮件地址
  • %ad:作者修订日期(可以用 --date=选项 来定制格式)
  • %ar:作者修订日期,按多久以前的方式显示
  • %cn:提交者的名字
  • %ce:提交者的电子邮件地址
  • %cd:提交日期
  • %cr:提交日期(距今多长时间)
  • %s:提交说明

查看具体commit

git show

查看任意一个commit

git show 5e68b0d8

show 后面加上这个 commit 的引用(branchHEAD 标记)或它的 SHA-1

看指定 commit 中的指定文件

# 在 commit 的引用或 SHA-1 后输入文件名
git show 5e68b0d8 demo.txt

看未提交的内容

  • 显示暂存区和上一条提交之间的不同
# 这条指令可以让你看到「如果你立即输入 git commit,你将会提交什么」
git diff --staged
或者
git diff  --cached
  • 显示工作目录和暂存区之间的不同
# 这条指令可以让你看到「如果你现在把所有文件都 add,你会向暂存区中增加哪些内容」
git diff
  • 工作目录和上一条提交之间的不同,它是上面这二者的内容相加
# 这条指令可以让你看到「如果你现在把所有文件都 add 然后 git commit,你将会提交什么」
git diff HEAD

查看某个远程仓库

#  git remote show <remote>
git remote show origin

它同样会列出远程仓库的 URL 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull, 就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支。 它也会列出拉取到的所有远程引用。

.gitignore

.gitignore文件用于排除不想被管理的文件和目录。文件中 # 打头的是注释文件,其他的都是对忽略文件的配置。

.gitignore 的格式规范如下:

  • 所有空行或者以 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf

tip: 当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆没用的文件添加到了暂存区,你可以这样做(这样不会删除文件,只是会让git不在继续跟踪)

# 移除README.md
 git rm --cached README.md

# 移除 log/ 目录下扩展名为 .log 的所有文件
 git rm log/\*.log
 
# 移除所有名字以 ~ 结尾的文件。  
git rm \*~

GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 github.com/github/giti… 找到它。这是一份适用前端项目的.gitignore文件

/[demo]/*

.DS_Store
node_modules
/dist

# local env files
.env.local
.env.*.local

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Editor directories and files
.vscode/*
!.vscode/settings.json
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

匹配规则

Pull Request

Pull Request 并不是 Git 的内容,而是一些 Git 仓库服务提供方(例如 GitHub)所提供的一种便捷功能,它可以让团队的成员方便地讨论一个 branch ,并在讨论结束后一键合并(Merge pull request)这个 branchmaster

参考资料

Git原理详解及实用指南

git-scm


👉 打破跨域限制,7种前端跨域解决方案全解析!

👉 浏览器进程和线程:前端开发工程师的必修课

👉 JavaScript 原型链完全解析,让你的代码更加高效

👉 一文搞懂前端请求XHR,AJAX,Fetch和Axios