git - noonecare/linux GitHub Wiki
工作区
工作目录
暂存区
.git/index 文件中记录的 树对象
版本库
.git 是本地版本库,版本库记录了历史。版本库如果不带工作区,就称为 裸版本库(empty repository)
对象
.git/Objects 下的内容。Git 对象有4种。所有的对象都有一个独一无二的ID(也称hash码)。这个ID通过 SHAI 算法计算得到。
提交
提交对象,记录了两种信息:提交时的目录(树对象表示),parent提交(提交对象)。
树对象
记录了发生修改的所有blob对象,相当于一个目录。
blob对象
记录了每个文件的修改信息。
tag对象
提交 ID 不好记, tag 算是提交ID的别名,也就是说你可以给提交起个 好记的名字(这个名字常常是软件的版本号)。tag 也就是常常说的里程碑。
HEAD
.git/HEAD 文件,一般这个文件的内容是分支的名称。但是也可以是一个任意的提交 ID 或者 tag。当 .git/HEAD 文件的内容不是分支的名称时。会提示 “头指针与分支分离”。
分支 分支是一个指向提交的记号
本地分支
.git/refs/heads目录下的文件。比如master, develop 等等,你打开这些文件,这些文件的内容时分支指向的提交的 ID 。
远程分支
.git/refs/remotes/目录下保存着远程版本库。远程版本库目录下保存着远程分支,远程分支同样是个文件,每个文件的内容都是某个提交的 ID。
跟踪
分支之间的关系。这种关系写在 git 配置文件 .git/config 中。建立了跟踪关系之后,执行 git status 时显示的是暂存区和当前分支所跟踪的分支有那些改动。通过跟踪关系可以实现版本库之间的同步,简单说就是执行嗯git push 和 git pull。
日志
git 在 .git/log 文件中记录了 HEAD 以及各个分支的指向历史。
引用表达式
fast-forward: 两个分支A,B 如果 A 的所有提交都是 B 的历史提交,或者 B 的所有提交都是 A 的历史提交,那么A, B合并是 fast-forward 的。
冲突
git 可以自动合并很多冲突,当自动合并不能解决冲突时,就需要你亲自决定如何解决冲突。解决冲突时可以根据冲突信息,直接用编辑器修改文件。也可以使用 git mergetool 命令调用 可视化的工具(比如kdiff3)去解决冲突。
配置文件
配置文件 .git/config git的配置文件是ini 格式的文件。 git config 可以显示和修改配置文件。git remote 可以显示和修改配置文件中的某些值。
下面的所有指令都可以,用 git help 查询如何使用。比如 git help add。通过查询,可以得到git 命令的准确的用法。下面,我不再重复这些内容,只是强调一下这些命令中最常用的用法。
git add 把变动添加到 index 。
git add 把 目录下的改动添加到 index。 git add -u
git commit
git commit -m
git tag 添加标签(里程碑)
git clone 克隆版本库
git clone [--bare] [--mirror]
git remote 显示/设置远程分支
git remote [-v] git remote add git remote rename git remote -d git remote set-url
git reflog
git stash
git stash git stash pop
git merge git fetch git pull git push git reset git checkout git rebase git diff git grep git cherry-pick git log git revert git clean up git mergetool git gc git add git rm
可能还会用到的一些命令有 git rev-parse git ls-file git cat-file git rev-list
引用表达式 < ref >@{< num >} 用在 git stash, git reflog 命令中。 HEAD@{< num >} 表示上 num 次 时, HEAD 的值。stash@{< num >}表示上 num 次 stash 的值。
< commit >^{< num >} commit 的第 num 个父提交
< commit >^{ tree } commit 的树对象
HEAD~{< num >}
< tag >^{ commit } tag 的commit
< commit1 >..< commit2 > 从 commit1 开始到 commit2 为止的所有提交
git cherry-pick 会把commits 提交的改动作为一个新的提交,提交到当前分支
构造根提交:
- git commit-tree < tree object > 创建一个只有 树对象, 没有父提交的提交,也就是根提交。常常用于丢弃历史提交。
- git hash-object 直接产生 hash 码的方法,用文件内容产生提交。
git rebase
将 commit2 的提交,依次提交到 commit 上。commit2的提交以 commit1的最后一次提交为父提交。
git merge
刷新 工作区,暂存区
git checkout 一般只是改写 HEAD 文件的内容,但是添加 option ,可以使得 git checkout 不仅改变 HEAD, 而且改变 index, 以及 工作区。
git reset --hard 表示改变 HEAD, index 以及工作区。 --soft 表示仅仅改变 HEAD, 不改变 暂存区和工作区。
git checkout 把工作区filename文件的改动丢弃,也就是说用 暂存区中的 filename 文件替换工作区中的filename文件。
git checkout HEAD 丢弃 暂存区和工作区中的 filename 文件的改动。也就是说用HEADcommit 中的filename文件替换工作区和暂存区中的 filename 文件。
git clean 把所有版本库没有跟踪的 工作区的文件删除。
git remote:
-
本地分支 当前版本库的分支
-
远程分支 remotes 目录下的分支
-
跟踪:建立分支时指定 --track 参数,可以跟踪分支。
-
同名:两个分支名称相同。
git push: 合并本地分支和远程分支,并且把远程分支复制到上游版本库。这里面最重要的问题,如何合并。
合并的本地分支是那些,合并的远程分支是那些: 这个和 git 的配置文件(可以用 git config push.default 来设置)push.default 参数有关。常见的 push.default 参数值有:
- simple, 合并的本地分支,是当前所在的分支。与之合并的远程分支是和 本地分支同名的远程分支,而且本地分支 track 远程分支。
- upstream, 与同不同名 无关,所有本地分支合并与被本地分支 track 的远程分支。
- nothing: 不推送任何东西
- current: 推送当前分支到远程分支的同名分支。
- matching: 推送本地版本库和远程版本库所有名字相同的分支。
git pull
git fetch
A 分支和 B 分支是否发生冲突,取决于: A1,A2, ... Am, B1, B2,...Bn B1,B2,... Bn, A1,A2,..., Am 的结果是否相同。 这样的话, 可以提交在某个分支中添加 提交来解决冲突(使得上面两个结果相同)。实际上也正是这样做的。
git cherry-pick: 我理解的git cherry-pick 是 把 提交 添加到分支上上的操作。 cherry-pick 可能会发生这样的 conflict, 比如 提交是 git rm data_sciene, 而当前 分支根本没有 datascience 文件,这就会报错。
验证修改的是内容还是只是相当于重复执行git指令。 cherry-pick 可以用来论证这个问题,在A分支中 写文件 a, 文件 a 的内容是 "a", 提交更改 git rm a。 在 B 分支中写个文件 a, 文件内容是 "b", 把 A 分支的 提交 cherry-pick 到 B 分支,如果顺利执行,说明 只是重复执行命令,如果不是说明 更改的是内容。我认为是后者。 果然如我所料,提交记住的是内容, 不是单纯的重复命令。
Git: 如果你做了错误的提交,最简单的办法是 git revert HEAD, 这样 git 会提交新的提交,新的提交会 undo 错误提交的更改。 但是,在本地版本库,我喜欢 git reset --hard HEAD^ 这样回滚到之前的提交,直接把错误的提交删掉。 现在 如果我已经把 错误的提交 push 到了远程版本库,有没有办法可以在远程版本库删掉 最开头的提交。 git push --force
你可以先把本地分支的提交删除,然后使用 git push 时,加上 --force 参数,强推,把 远程分支相应的提交也删除。
git push --delete
- git push --delete HEAD 把远程的 HEAD 提交(最新提交)删除。
git reset HEAD^
git push orign +HEAD