0%

动画学Git https://learngitbranching.js.org/

Git基础

安装介绍,仅针对编译安装方法。

  1. 下载获取git源码 https://github.com/git/git/releases

    wget https://github.com/git/git/archive/refs/tags/v2.31.0.tar.gz
    
    tar -zxvf v2.31.0.tar.gz
    
    cd git-2.31.0
  2. 准备依赖包

    yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker nss curl libcurl
  3. 开始安装

    mkdir -p /usr/local/git
    
    make prefix=/usr/local/git all
    make prefix=/usr/local/git install
  4. 配置环境变量

    echo "export PATH=\$PATH:/usr/local/git/bin" >> /etc/profile
    
    source /etc/profile

获取Git仓库

  1. 将尚未进行版本控制的本地目录转换为Git仓库

    cd /home/gitdemo/
    git init
  2. 从其他服务器克隆一个已存在的Git仓库

    cd /home/
    git clone https://github.com/gitdemo/gitdemo

无论是本地初始化仓库还是从远程获取一个仓库,都会在目录下初始化一个**.git**文件夹,其中保存着仓库的所有内容和版本控制相关的数据。

记录每次更新到仓库

工作目录下的每一个文件都不外乎这两种状态:未跟踪已跟踪
已跟踪的文件是指那些被纳入版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 Git 已经知道的文件。
工作目录中除已跟踪文件外的其它所有文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有被放 入暂存区。
初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态,因为 Git 刚刚检出了它们, 而你尚未编辑过它们。


git add 命令的作用:1. 跟踪新文件 2. 将已跟踪的文件放至暂存区

所以将 git add 命令理解为“精确的将内容添加到下一次提交中”,而不是“将一个文件添加到项目中”要更加合适。

查看当前状态


git stash

On branch master 所在分支
Your branch is up-to-date with 'origin/master'.

Changes to be committed: 在这行下面的文件或文件夹,说明是一暂存状态。
  (use "git reset HEAD <file>..." to unstage)
  new file: README

Changes not staged for commit: 这行下面的文件或文件夹,说明已跟踪文件的内容发生了变化,但还灭有放到暂存区。
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)
  modified: CONTRIBUTING.md

Untracked files: 这行以下的文件或文件夹,处于未跟踪状态,如果不进行add操作,将永远不会commit到本地仓库
  (use "git add <file>..." to include in what will be committed)
  README
nothing added to commit but untracked files present (use "git add" to
track)

简要输出状态信息:git status --short / -s


git stash --short / -s

 M README 右M标记:文件在工作区已修改,但尚未暂存
MM Rakefile MM标记:文件已修改,暂存后又进行了修改
A lib/git.rb A标记:新添加到暂存区的文件
M lib/simplegit.rb 左M标记:文件已修改且已暂存
?? LICENSE.txt ??标记:新添加的未跟踪文件

忽略文件

.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

查看已暂存和未暂存的修改

git diff 此命令比较的是工作目录中当前文件和暂存区域快照之间的差异。也就是修改之后还没有暂存起来的变化内容。

git diff --staged / --cached 加上该参数后,将比对已暂存文件与最后一次提交的文件差异。

提交更新

git commit 打开默认编辑器,编辑提交说明后,退出编辑器,即可完成提交。

git commit -m "提交说明" 通过-m参数可以直接在终端输入提交说明,完成提交。

跳过使用暂存区域

git commit -a 加上-a参数,Git会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过git add步骤。(tips:请小心使用,确保你知道当前有哪些文件会被自动add,避免将不需要的文件添加到提交中)

移除文件

git rm 将文件从暂存区中移除,并连带从工作目录中是删除指定文件,下次提交时,该文件将不再纳入版本管理。

git rm -f / --force 通过添加-f参数,可以将之前修改过或已经放到暂存区的文件强制删除。(这是一种安全特性,用于防止误删尚未添加到快照的数据,这样的数据不能被Git恢复。)

git rm --cached 该参数只将文件从暂存区中移除,工作目录中任然保留。

移动文件

git mv 移动文件到指定位置,或者更改文件名,用于与linux中的mv命令类似。

该命令实际上完成了三次操作,例如 git mv README.MD README 等价于如下操作:

  1. mv README.MD README
  2. git rm README.ME
  3. git add README

查看提交历史

git log 根据时间先后顺序列出所有提交信息,包括每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。

git log -p / --patch 该参数会显示每次提交所引入的差异(按 补丁 的格式输出)

git log -n 表示显示最近的n次提交信息,-2 表示显示最新的两次提交信息。

git log --stat 在每次提交的下面列出所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加了,最后附上一个总结统计。

git log --pretty-[oneline | short | full | fuller] 使用不同的默认格式展示历史提交信息,不同选项 格式基本一致,但是详细程度不同。

git log --pretty-format:"%h - %an, %ar : %s" 通过指定参数组合出想要的格式化输出

git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

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

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

git log --pretty=format:"%h %s" --graph 通过组合format和graph可以以图的形式展示格式化信息

git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
* 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
* 11d191e Merge branch 'defunkt' into local

git log的常用选项

选项说明
-p按补丁格式显示每个提交引入的差异。
--stat显示每次提交的文件修改统计信息。
--shortstat只显示 --stat 中最后的行数修改添加移除统计。
--name-only仅在提交信息后显示已修改的文件清单。
--name-status显示新增、修改、删除的文件清单。
--abbrev-commit仅显示 SHA-1 校验和所有 40 个字符中的前几个字符。
--relative-date使用较短的相对时间而不是完整格式显示日期(比如“2 weeks ago”)。
--graph在日志旁以 ASCII 图形显示分支与合并历史。
--pretty使用其他格式显示历史提交信息。可用的选项包括 oneline、short、full、fuller和format(用来定义自己的格式)。
--oneline--pretty=oneline --abbrev-commit 合用的简写。

限制输出长度

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

git log --until=2.weeks / --before=2.weeks 列出最开始到两周之前的所有提交

git log --since="2021-03-16" 列出从2021-03-16这天的现在这个时间点到现在的所有提交

git log --since="2021-03-16 11:00:00" 列出从2021-03-16 11:00:00到现在的所有提交

git log --author=xiao 列出作者名或email中包含xiao的所有提交,支持正则表达式,--author="A|B" 表示包含A或者包含B。

git log --grep="fix bug" 列出提交内容中包含“fix bug”关键字的所有提交

git log --author="小明" --grep="fix bug" 列出提交人是小明 and 提交内容包含“fix bug”关键字的所有提交

git log --grep=fix --grep=bug 列出提交内容包含fix or 提交内容包含bug 关键字的所有提交

git log --grep=fix --grep=bug --all-match 列出提交内容包含fix and 提交内容包含bug 关键字的所有提交,--all-match仅对--grep有效

git log -S function_name 列出添加或删除了function_name这个指定字符串的提交

git log -G *function_name* 与-S不同的是,-G支持正则表达式

git log -- Test.java 列出改动过当前目录下Test.java文件的所有提交,-- 后面为文件或目录的路径

git log branchName -- 查看branchName分支上的提交记录,-- 前面为分支名称

git log branchName -- filepath 查看branchName分支上,关于filepath的提交记录,-- 前面为分支名称,-- 后面为文件或文件夹路径

git log commit 查询commit之前的提交记录,包含commit,commit可以是提交的hash值,也可以是HEAD

git log commit1 commit2 查询commit1与commit2之间的记录,包括commit1和commit2

git log commit1..commit2 同上,但不包括commit

限制git log输出的选项

选项说明
-<n>仅显示最近的 n 条提交。
--since,--after 仅显示指定时间之后的提交。
--until,--before 仅显示指定时间之前的提交。
--author仅显示作者匹配指定字符串的提交。
--committer仅显示提交者匹配指定字符串的提交。
--grep仅显示提交说明中包含指定字符串的提交。
-S仅显示添加或删除内容匹配指定字符串的提交。

按照你代码仓库的工作流程,记录中可能有为数不少的合并提交,它们所包含的信息通常并不多。 为了避免显示的合并提交弄乱历史记录,可以为 log 加上 --no-merges 选项。

撤销操作

git commit --amend 将如果在提交完成之后又进行了改动,并且不想重新提交;或者上一次的提交信息写错了,想要重写并覆盖之前的提交,就可以使用该命令完成。这个命令会将暂存区中的文件提交。如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令),那么快照会保持不变,而你所修改的只是提交信息。该命令执行完成之后,上一个提交将会消失,git会产生一个新的提交,可以从hash值中了解到。

取消暂存的文件

git restore --staged filename 将已暂存的文件转变为已修改为暂存的文件

撤销对文件的修改

git restore filename 撤销未暂存文件的所有修改,将文件还原成上次提交时的样子。

记住,在 Git 中任何 已提交 的东西几乎总是可以恢复的。 甚至那些被删除的分支中的提交或使用 --amend 选 项覆盖的提交也可以恢复 (阅读 数据恢复 了解数据恢复)。 然而,任何你未提交的东西丢失后很可能再也找不到了。

远程仓库的使用

远程仓库可以在你的本地主机上
你完全可以在一个“远程”仓库上工作,而实际上它在你本地的主机上。 词语“远程”未必 表示仓库在网络或互联网上的其它位置,而只是表示它在别处。 在这样的远程仓库上工作,仍然需要和其它远程仓库上一样的标准推送、拉取和抓取操作。

查看远程仓库

git remote 列出指定的每个远程服务器的简写,一般默认是origin,这是Git设置的默认名字。

git remote -v 会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。

git remote -v

origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)

如果你的远程仓库不止一个,该命令会将它们全部列出。 例如,与几个协作者合作的,拥有多个远程仓库的仓库看起来像下面这样:

git remote -v

bakkdoor https://github.com/bakkdoor/grit (fetch)
bakkdoor https://github.com/bakkdoor/grit (push)
cho45 https://github.com/cho45/grit (fetch)
cho45 https://github.com/cho45/grit (push)
defunkt https://github.com/defunkt/grit (fetch)
defunkt https://github.com/defunkt/grit (push)
koke git://github.com/koke/grit.git (fetch)
koke git://github.com/koke/grit.git (push)
origin git@github.com:mojombo/grit.git (fetch)
origin git@github.com:mojombo/grit.git (push)

添加远程仓库

git remote add 添加一个新的远程Git仓库,同事指定一个方便使用的简写名称

$ git remote
origin

$ git remote add pb https://github.com/paulboone/ticgit

$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)

从远程仓库中抓取与拉取

git fetch 这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支 的引用,可以随时合并或查看。

git fetch 命令只会 将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。

如果你的当前分支设置了跟踪远程分支(阅读下一节和 Git 分支 了解更多信息), 那么可以用 git pull 命令来自动抓取后合并该远程分支到当前分支。 这或许是个更加简单舒服的工作流程。默认情况下,git clone 命 令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或其它名字的默认分支)。 运行 gitpull 通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。

推送到远程仓库

git push 将你本地的branch分支推送到origin服务器上

只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。 当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先抓取他们的工作并将其合并进你的工作后才能推送。

查看某个远程仓库

git remote show 查看remote仓库的详细信息

git remote show origin
* remote origin
  URL: https://github.com/my-org/complex-project
  Fetch URL: https://github.com/my-org/complex-project
  Push URL: https://github.com/my-org/complex-project
  HEAD branch: master
  Remote branches:
  master tracked
  dev-branch tracked
  markdown-strip tracked
  issue-43 new (next fetch will store in remotes/origin)
  issue-45 new (next fetch will store in remotes/origin)
  refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
  dev-branch merges with remote dev-branch
  master merges with remote master
  Local refs configured for 'git push':
  dev-branch pushes to dev-branch (up to date)
  markdown-strip pushes to markdown-strip (up to date)
  master pushes to master (up to date)

这个命令列出了当你在特定的分支上执行 git push 会自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了, 还有当你执行 git pull 时哪些本地分支可以与它跟踪的远程分支自动合并。

远程仓库的重命名与移除

git remote rename a b 将远程仓库a重命名为b,该操作会修改你所有远程跟踪的分支名字。那些过去引用a/master的现在会引用b/master。

git remote remove a 删除远程仓库a,使用这种方式删除一个远程仓库,那么所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除。

打标签

待补充

别名

git config alias.unstage 'restore --staged' 设置unstage别名对应'git restore --staged'命令,在定义别名时,git可以省略。该别名仅对当前仓库有效。如果希望对所有仓库有效的话,需要在config后面加上--global参数。

定义好unstage别名后,以下两个命令等价:

git unstage file

git restore --staged file

Git分支

分支的新建

git checkout -b branch_name

等价于

git branch branch_name
git checkout branch_name

分支的合并

合并分支feature/do_something到当前分支

git merge feature/do_something

合并时发生冲突

git merge feature/do_something

Git工具

自定义Git

Git内部原理