git commit
主要是将暂存区的改动提交到本地版本库,通常结合 -m 描述此次提交的原因
git commit -m '提交原因'
修改已提交的节点
git commit --amend
git branch
创建一个名为newBranch的分支
git branch newBranch
以直接使用 -f
选项让分支指向另一个提交
比如将master分支强制指向newBranch
git branch -f master newBranch
git checkout
可以切换当前分支到指定分支
git checkout newBranch
如果添加参数 -b,则可以创建一个分支并切换到该分支上
git checkout -b newBranch2
git merge
在 Git 中合并两个分支时会产生一个特殊的提交记录,它有两个父节点。
比如当前分支为master,现在将newBranch合并到master分支上
git merge newBranch
git rebase
Rebase 实际上就是取出当前分支一系列的提交记录,“复制”它们,然后在另外(指rebase后指定的分支)一个地方逐个的放下去。
Rebase 的优势就是可以创造更线性的提交历史,这听上去有些难以理解。如果只允许使用 Rebase 的话,代码库的提交历史将会变得异常清晰。
比如当前分支为bewBranch,将此分支完全合并到master
git rebase master
交互式 rebase 指的是使用带参数 --interactive
的 rebase 命令, 简写为 -i
如果你在命令后增加了这个选项, Git 会打开一个 UI 界面并列出将要被复制到目标分支的备选提交记录,它还会显示每个提交记录的哈希值和提交说明,提交说明有助于你理解这个提交进行了哪些更改。
git rebase -i HEAD~4 # 调整包括当前节点的共4个节点的提交记录
HEAD
默认指向最近的一次提交,可通过checkout其他分支(通过哈希值,git log可查询)分离出来。
例如某个提交的哈希值是C3,将HEAD移动到C3上去
git checkout C3
通过哈希值定位的方法有些许麻烦,HEAD支持相对引用。
- 使用
^
向上移动 1 个提交记录
- 使用
~<num>
向上移动多个提交记录,如~3
首先看看操作符 (^)。把这个符号加在引用名称的后面,表示让 Git 寻找指定提交记录的父提交。
所以 master^
相当于“master
的父节点”。
master^^
是 master
的第二个父节点
git reset
通过把分支记录回退几个提交记录来实现撤销改动,向上移动分支,原来指向的提交记录就跟从来没有提交过一样。
只保留到C3的更改
git reset C3 # reset后可以跟哈希值,也可以跟分支名
git revert
虽然在你的本地分支中使用 git reset
很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效的哦!
为了撤销更改并分享给别人,我们需要使用 git revert
。
在我们要撤销的提交记录后面居然多了一个新提交!这是因为新提交记录 C2'
引入了更改 —— 这些更改刚好是用来撤销 C2
这个提交的。也就是说 C2'
的状态与 C1
是相同的。
revert 之后就可以把你的更改推送到远程仓库与别人分享啦。
git revert C2 # 撤销C2的修改
git cherry-pick
如果你想将一些提交复制到当前所在的位置(HEAD
)下面的话, Cherry-pick 是最直接的方式了。我个人非常喜欢 cherry-pick
,因为它特别简单。
git cherry-pick C3 C4 # 在当前分支,以C3 ---> C4的顺序,赋值两个节点的更改,生成 # 新的节点C3' ---> C4'紧接着当前分支
git tag
分支很容易被人为移动,并且当有新的提交时,它也会移动。分支很容易被改变,大部分分支还只是临时的,并且还一直在变。
有没有什么可以永远指向某个提交记录的标识呢,比如软件发布新的大版本,或者是修正一些重要的 Bug 或是增加了某些新特性,有没有比分支更好的可以永远指向这些提交的方法呢?
当然有了!Git 的 tag 就是干这个用的啊,它们可以(在某种程度上 —— 因为标签可以被删除后重新在另外一个位置创建同名的标签)永久地将某个特定的提交命名为里程碑,然后就可以像分支一样引用了。
更难得的是,它们并不会随着新的提交而移动。你也不能检出到某个标签上面进行修改提交,它就像是提交树上的一个锚点,标识了某个特定的位置。
git tag v1 C1 # 将节点C1标记为V1
git clone
第一个事就是在我们的本地仓库多了一个名为 o/master
的分支, 这种类型的分支就叫远程分支。由于远程分支的特性导致其拥有一些特殊属性。
远程分支反映了远程仓库(在你上次和它通信时)的状态。这会有助于你理解本地的工作与公共工作的差别 —— 这是你与别人分享工作成果前至关重要的一步.
远程分支有一个特别的属性,在你检出时自动进入分离 HEAD 状态。Git 这么做是出于不能直接在这些分支上进行操作的原因, 你必须在别的地方完成你的工作, (更新了远程分支之后)再用远程分享你的工作成果。
git fetch
git fetch
完成了仅有的但是很重要的两步:
- 从远程仓库下载本地仓库中缺失的提交记录
- 更新远程分支指针(如
o/master
)
git fetch
实际上将本地仓库中的远程分支更新成了远程仓库相应分支最新的状态。但是本地仓库并不是最新状态
当远程分支中有新的提交时,你可以像合并本地分支那样来合并远程分支。也就是说就是你可以执行以下命令:
git cherry-pick o/master
git rebase o/master
git merge o/master
git pull
实际上,由于先抓取更新再合并到本地分支这个流程很常用,因此 Git 提供了一个专门的命令来完成这两个操作。它就是我们要讲的 git pull
。
在本地仓库的master上,使用git pull即可
git pull
git push
git push
负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。
git push
如果本地仓库与远程仓库出现了冲突,可以使用rebase或merge解决冲突再提交到远程仓库
git rebase origin
或者
git merge origin
有个更简单的指令
git pull --rebase
然后
git push
练习
将图一变成图二的状态
图一:
图二:
要求
操作步骤:
git fetch git rebase o/master side1 git rebase side1 side2 git rebase side2 side3 git rebase side3 master git push
指定分支跟踪远程分支
git checkout -b totallyNotMaster o/master
# 就可以创建一个名为totallyNotMaster
的分支,它跟踪远程分支o/master
。
另一种设置远程追踪分支的方法就是使用:git branch -u
命令,执行:
git branch -u o/master foo
这样 foo
就会跟踪 o/master
了。如果当前就在 foo 分支上, 还可以省略 foo:
git branch -u o/master
git push origin master
把这个命令翻译过来就是:
切到本地仓库中的“master”分支,获取所有的提交,再到远程仓库“origin”中找到“master”分支,将远程仓库中没有的提交记录都添加上去,搞定之后告诉我。
我们通过“place”参数来告诉 Git 提交记录来自于 master, 要推送到远程仓库中的 master。它实际就是要同步的两个仓库的位置。
需要注意的是,因为我们通过指定参数告诉了 Git 所有它需要的信息, 所以它就忽略了我们所检出的分支的属性!
以下命令在 Git 中是等效的:
git pull origin foo
相当于:
git fetch origin foo; git merge o/foo
还有...
git pull origin bar~1:bugFix
相当于:
git fetch origin bar~1:bugFix; git merge bugFix