分支

merge

存在两种merge操作,分别为fast-forward(--ff)和no-fast-forward(--no-ff).

前者默认发生在当前分支没有相对于待合并分支的额外结点时,此时不会发生新的commit,只是向前移动当前分支指针。

后者默认发生在其他情况下,此时会产生一个新的commit,其拥有两个父结点,分别位于两个分支中。如果出现冲突还需要手动解决。

rebase

rebase将当前分支的提交复制到另一分支之后。此过程中,被复制的commit会重新生成hash值.

interactive rebase可以以当前分支中的commit为参数,并且可以对需要复制的commit进行修改.

cherry-pick

git cherry-pick [commit id]在当前分支下新增一个commit,其内容与指定的commit相同.

HEAD指针是一个symbolic reference(符号引用,快捷方式),指向分支名或者一次commit. 通常情况下HEAD总是指向分支名,这意味着其指向当前分支最近一次commit.

git checkout [commit id]分离头指针使其指向某次commit而非分支名(commit用其hash值指定,且仅需前6位).

cat .git/HEAD查看当前HEAD指向.

git symbolic-ref HEAD查看当前HEAD指向(仅限HEAD指向分支名时,即HEAD->master->Commit_1)

相对引用

使用^表示指定引用的父节点,如HEAD^ master^

使用~<num>表示向上移动多次,如HEAD~3

配合git branch -f [branch name] [ptr]强制移动(非当前)分支指针位置,如git branch -f master HEAD~3

撤销变更

git reset [ptr]将当前分支HEAD移动到指定位置,如git reset HEAD^.从新位置到旧位置之间的提交仍存在,处于未加入暂存区的状态;但是如果使用--hard参数,这些提交会消失.这种方式往往应用于个人维护的分支.

git revert [ptr]以添加一个新commit的形式撤销ptr指向的提交,因此添加新提交后的状态与ptr的父节点相同.这种方式往往应用于多人协作分支,因为它不会导致提交历史的改变.

标签

鉴于分支可以轻易地被移动和更改,引入了tag的概念。tag是一个永久指向某个提交记录的标识,不会随着新的提交而移动.git tag [tagname][ptr]将名为tagname的tag打在ptr指向的commit上.

git describe [ptr] 返回离ptr指向的commit最近的tag,格式为<tag>_<numCommits>_g<hash>,其中<tag>是离ptr最近的标签,<numCommits>表示ptr与这个标签之间相差多少个commit,<hash>是ptr指向的commit的hash值.

reflog

git reflog展示分支的操作历史,可以配合git reset实现撤销操作。

远程分支

远程分支位于本地仓库中,反映了最后一次与远程仓库通信时的状态。

远程分支的命名规范是<remote name>/<branch name>,默认的远程仓库名是origin.

远程分支在成为checkout的目标时会自动进入分离HEAD状态,这是为了让远程分支不能成为直接操作的对象。

git clone时会自动为远程仓库中的每一个分支,在本地仓库中创建一个远程分支并加以关联。

git fetch origin master从远程仓库下载本地缺失的提交记录并移动本地的origin/master远程分支指针;本地仓库不会发生改变,即master分支不变,文件不会被修改。

不带参数的git fetch将各commit下载到对应的分支里。

git pull相当于git fetch加上git merge,效果是与远程仓库同步。

git push <remote> <place>(如git push origin master)表示找到本地master分支中的所有提交,向远程仓库origin的master分支中添加其中不存在的提交.<place>参数指定了要同步的两个分支的位置。

一般的命令是git push <remote> <source>:<destination>,适用于本地远程分支与关联的远程仓库中的分支不同名的情况。如果<source>留空,会删除远程仓库的<destination>分支。

当本地仓库基于过时的远程仓库时

git pull --rebase相当于git fetch加上git rebase origin/master,效果是获取远程仓库的提交记录后,将当前分支的工作转移到最新的远程分支下。

git pull相当于git fetch加上git merge origin/master,效果与前者一样,不过会引入一次新的合并而非移动当前分支的工作。

参考资料

  1. https://learngitbranching.js.org/

  2. https://dev.to/lydiahallie/cs-visualized-useful-git-commands-37p1