Git学习
关联本地仓库和远程仓库并进行push
1 | git remote add <reposiotry-name> <url> |
1 | git push <remote-repository> <local-branch>:<remote:branch> |
克隆刚刚push的仓库修改后再push
1 | git clone <remote-repository-url> <target-directory> |
1 | 修改其中的sample.txt文件 |
1 | git push |
git diff,比较工作区和暂存区的文件之间的差异。
以暂存区的文件作为参照物来描述工作区的文件的差异。
同理git diff --staged,比较暂存区和存储区的差异,以存储区作为参照物
在Git中,代码的管理围绕提交记录进行
提交记录就是一个提交对象,提交对象包含了很多信息,比如提交时的注释、指向上一个提交对象的指针、指向树对象的指针。
项目结构树对象,其上的根节点和分支节点其实就是目录或者说文件夹。而其叶子节点指向实际的文件对象,文件对象实际上就是blob对象
blob对象,就是实际的文件对象
项目结构树对象和若干个blob对象就组成了一次提交时产生的暂存内容的快照,提交对象虽然说实际上指向的是树对象,但也可以说指向的是这次提交产生的快照
分支,就是一个指针,这个指针指向提交对象,比如说master,本质就是一个指针,通常情况下指向最新的一次提交对象。因为分支实际是指针,所以在Git中,称分支为ref,引用
HEAD,也是一个指针,这个指针可以指向分支,也可以指向提交对象
特别需要说明的是,比如说HEAD^,通常说是上一个节点,但是HEAD哪来的上一个节点?假设这时的情况是HEAD->master->commit1,commit1是有上一个节点的,所以这个过程是从HEAD递归寻找到其最终指向的一个提交对象,然后然后得出该提交对象的上一个提交对象,即commit0。这有点像运算符重载。同理master^也是一样。ref^与ref~n运算的结果都是提交对象
git checkout <ref>/<commit>命令,用来修改HEAD的指向,后面跟一个分支名或者一个提交对象。
1 | git checkout main # 让HEAD指向分支main |
git branch -f <ref1> <commit>/<ref2>/HEAD命令,改变分支ref1的指向,后面跟一个提交对象或者另一个分支。注意分支最终指向的一定是提交对象,所以这里第二个参数为分支或HEAD也有点递归的意思。
1 | git branch -f main <commit> # 让分支main指向某次提交 |
git reset <commit>/<ref>命令,这个命令是修改当前HEAD所指向的分支的指向,但是HEAD的指向仍然是刚才的分支不会变。比如此时HEAD->main->c1,用了这个命令后HEAD->main->c0,也有点递归的意思
1 | git reset master # 假如此前HEAD->main->c1,master->c0; 此后HEAD->main->c0 |
git cherry-pick <commit>/<ref>命令,复制其它分支上的提交对象,commit 到当前HEAD所指向的分支,比如此时HEAD->main->c1,master->c2,使用命令后HEAD->main->c2->c1'
1 | HEAD->main-><commit> |
git rebase <ref>命令,修改当前HEAD所指向的分支的基。Git会找到当前分支与参数中ref分支的第一个公共祖先节点,然后把当前分支指向的节点之前的提交对象做一个拷贝,把拷贝的对象都移到ref指向的提交对象的后面,最后修改当前分支的指向到最后一个拷贝对象上,注意HEAD的指向的还是当前分支不变,由此实现变基。加了-i或者--iteractive还可以打开交互式GUI界面,改变当前分支指向的节点到公共祖先节点之间的节点的顺序,或者删除节点
1 | HEAD->main->c4->c3->c1,master->c2->c1 |
git rebase <ref1> <ref2>
1 | git rebase <ref1> <ref2> # 把<ref2>分支变基到<ref1>分支上 |
git commit --amend命令,只会再次提交一次当前HEAD指向的提交对象,然后修改分支指向,不会影响后面子提交的父指向
1 | c3->c2->c1. HEAD->main->c2->c1 |
git describe <commit>/<ref>/HEAD,描述离指定节点最近的一次有tag的节点
git checkout main; git meerge master,合并的新节点属于main分支,也就是HEAD->main-><new-commit>
git fetch 完成了仅有的但是很重要的两步:
- 从远程仓库下载本地仓库中缺失的提交记录
- 更新远程分支指针(如
origin/main)
git fetch 不会做的事
git fetch 并不会改变你本地仓库的状态。它不会更新你的 main 分支,也不会修改你磁盘上的文件。
先抓取更新再合并到本地分支
这个流程指的是先git fetch,
再执行以下命令:
git cherry-pick orign/maingit rebase orign/maingit merge orign/main- 等等
但是,git pull合并了这两步操作
git pull 就是 git fetch 和 git merge 的缩写!
git pull --rebase 就是 git fetch 和 git rebase 的简写!
git push 负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。
git push默认会把当前HEAD指向的分支上的所有节点提交到远程仓库,在远程仓库修改或创建同名分支,在本地仓库修改或创建origin/<ref>远程分支以同步远程仓库
- pull 操作时, 提交记录会被先下载到 o/main 上,之后再合并到本地的 main 分支。隐含的合并目标由这个关联确定的。
- push 操作时, 我们把工作从
main推到远程仓库中的main分支(同时会更新远程分支o/main) 。这个推送的目的地也是由这种关联确定的!
直接了当地讲,main 和 o/main 的关联关系就是由分支的“remote tracking”属性决定的。main 被设定为跟踪 o/main —— 这意味着为 main 分支指定了推送的目的地以及拉取后合并的目标。
当你克隆时, Git 会为远程仓库中的每个分支在本地仓库中创建一个远程分支(比如 o/main)。然后再创建一个跟踪远程仓库中活动分支的本地分支,默认情况下这个本地分支会被命名为 main。
这也解释了为什么会在克隆的时候会看到下面的输出:
1 | local branch "main" set to track remote branch "o/main" |
可以让任意分支跟踪 o/main, 然后该分支会像 main 分支一样得到隐含的 push 目的地以及 merge 的目标。 这意味着你可以在分支 totallyNotMain 上执行 git push,将工作推送到远程仓库的 main 分支上。
有两种方法设置这个属性,第一种就是通过远程分支切换到一个新的分支,执行:
1 | git checkout -b totallyNotMain o/main |
就可以创建一个名为 totallyNotMain 的分支,它跟踪远程分支 o/main。
另一种设置远程追踪分支的方法就是使用:git branch -u 命令,执行:
1 | git branch -u o/main foo |
这样 foo 就会跟踪 o/main 了。如果当前就在 foo 分支上, 还可以省略 foo:
1 | git branch -u o/main |
