Git 学习沉淀
1. 概述
使用了Git作为项目的管理工具也有些日子了,Git作为一个很Nice的工具,其有繁杂的命令,但实际上在项目中使用且实用的命令并不多,或者说并不难掌握,只是有些命令是组合套路,容易遗忘。
所以,本篇主要是记录一些学习Git中的笔记,便于日后翻阅,拾起来。
2. 基本知识
首先,使用的Git作为版本管理的工作目录(项目根目录)都有一个隐藏文件: .git
,
这个隐藏文件是Git工具的核心,它保存了项目所有的变动。
-
Git 初始化配置的套路
查看Git的所有的初始化配置
$ git config --list
查看所有的初始化配置信息会有重复的数据(分为全局配置和局部配置),不利于我们得到真正想要的信息。
所以,我们可以查看Git的单个初始化配置(类似于继承重载)
$ git config user.name
配置Git的关键信息,user.name & user.email
$ git config --global user.name “wxsmile”
$ git config --global user.email “wxsmile@nb.com” -
理解Git中的几种状态
Untracked files
: 未跟踪的文件
changes to be commited
: 可以提交的改动
changes not staged for commit
: 不可提交的改动
commited
: 已提交的改动
3. 上手
-
一次简单的Git流程
$ git init
$ git add .
$ git commit -m “commit message”
$ git push -
团队中的一次简单Git流程
git clone [url] [alias name]
$ git clone https://github.com/…/git-project.git myproject
$ git add .
$ git commit
$ git pull
$ git push -
push的本质
直观上,push是将本地的commit上传到中央仓库,用本地的内容覆盖远端的内容。
实质上,push是将当前branch以及其上所有的commits一并上传。
一般操作:
$ git checkout feature-some
$ git push
$ git push origin master
$ git push origin develop -
merge的本质
merge就是,把目标commit所属的分支上的所有commits应用到当前分支
一次简单的合并操作
$ git checkout -b feature-some
$ git add.
$ git commit
$ git checkout master
$ git add.
$ git commit
$ git merge feature-some一次简单的快速前移fast-forward(ff)
$ git checkout -b new-feature
$ git add.
$ git commit
$ git checkout master
$ git merge new-feature -
add的本质
一般操作
$ git add a.txt
$ git commit查看commit的简要统计
$ git log --stat
a.txt | 1+
1 file changed, 1 insertion(+)本质上是a.txt文件的内容变动记录用于被提交,而不是文件名。
对比工作目录和暂存区
$ git diff
$ git diff staged
4. 一些有点难度但是常用的东西
-
优雅的修正上一个糟糕的commit, 类似如下
$ git add a.txt
$ git commit -m “买了女装” (一次糟糕的提交)
修改a.txt…
$ git add a.txt
$ git commit --amend (优雅的修复上一次糟糕的提交)值得注意的是,这种操作不是直接修改原commit的内容,而是会产生一个新的commit,然后覆盖原来糟糕的commit。
-
修正上上次的糟糕提交,用到 rebase -i [目标commit]
这种操作叫做:交互式变基
譬如该分支倒数第二个commit是一个糟糕的commit
$ git rebase -i head^^
执行之后,跳到如下编辑界面:
主要看里面的commands, 看英文说明,已经说得很清楚了,这里将pick改为edit,表示继续使用该条commit并且停止以便于amending。
保存退出,那么当前状态处于一个类似阻塞的状态,然后让我们修正糟糕的提交。
所以,修正完之后:$ git add .
$ git commit --amend
$ git rebase --continue值得注意的一点就是,如果当前分支所有的commit已经push到中央仓库,该操作会导致后续
git push
遭遇 [push reject],原因是中央仓库之后包含本地没有的commit,这个commit就是刚刚被替换掉的commit,这种情况需要用到:$ git push origin branch -f
这种操作是明确本地commit就是想要的,然后强制覆盖中央仓库的commit,一般情况下(团队多人项目、分支),还是慎用。
-
舍弃一次无比无比糟糕的提交
舍弃某次糟糕提交之后的所有提交
git reset --hard [目标commit]
$ git reset --hard head^
舍弃指定糟糕的提交
git rebase -i [目标commit]
,然后使用command: drop, 保存退出。还可以,使用
rebase --onto [基点commit] [起点commit] [终点commit]
来做:
譬如当前master分支上有 [commit1、commit2、commit3、commit4]。
现在我需要舍弃commit3这次糟糕的commit$ git rebase --onto commit2 commit3 master
起点提交 commit3 在执行之后被舍弃,变为:
[commit1、commit2、commit5] -
处理已经push到中央仓库的commit
git revert [目标commit]
$ git revert head^
有意思的一点是,这个操作不会删除目标commit,而是会生成一个新的commit,这个commit和目标commit的内容是相反的,形成反转,达到撤销的效果。
-
reset 本质
reset --hard [目标commit]
我们知道可以用来撤销某次糟糕的撤销,但是其本质不仅仅是如此。事实上,这个操作的本质是将当前HEAD以及branch移动到[目标commit]。
而reset的 参数也有讲究,譬如我们用到的 <–hard> ,它在移动HEAD和branch的同时,还会舍弃掉当前[未提交]
状态的所有改动。所以,它还有另外的参数 <–soft> , 表示保留原来状态为
[changed to be commit]
的改动,以及将移动HEAD之后带来的差异commit内容置为[changes to be commit]
。如果reset不带参数,和<–soft> 类似,只是所有[changes to be commit]状态变为[changed not staged for commit]。
-
reset 和checkout的不同
二者都是改变HEAD的位置,区别在于reset会带着branch一起移动,而checkout将使HEAD与当前branch脱离直接指向某个commit。
-
临时存放工作目录的变动
当工作目录有了一些改动,但是这些改动还不注意构成一次提交时,可以使用git stash -u
命令$ git stash -u
$ git checkout master-u 是 --include-untracked 的简写,意思是状态为[untracked files] 也会被临时存放
当再次回来时,可以恢复临时存放的工作目录的变动
$ git checkout new-feature
$ git stash pop多个分支存在任务的时候,git stash的用法
git stash save -u “feature1 temp message”
git checkout feature2
git stash save -u “featrue2 temp message”
git checkout feature1
git stash list
git stash pop stash@{id} -
恢复刚删除的branch
不小心手残删除了一个还有用的branch?
$ git reflog
该操作是查看仓库的HEAD引用移动记录,然后找到删除branch变动之前的commit,使用 checkout命令检出这个commit, 重新创建branch。
$ git checkout
$ git checkout -b branch-1值得注意的是,不再被引用的branch或者commit,在一段时间之后会被Git回收,所以这种操作一定要及时。
-
cherry-pick
当Git工作目录包含IOS、Android、React-Native等大杂烩时,只需要合并指定commit,比如只合并Android相关的commits?$ git cherry-pick [Android Commit1] [Android Commit2] …
-
使用git fetch和git rebase处理多人开发同一分支的问题
当多人在同一分支开发时,如果在远程分支其他人先于自己push了一些提交,这时候自己的push会被拒绝而失败。
所以,一般我们会git pull操作,然后git push,我们知道git pull是 git fetch和 git merge的组合操作,是先同步远程分支到本地,然后将远程分支和本地分支合并,这样最后会在本地产生一个额外的Commit,其message形如:“Merge branch ‘feature/a’ of origin/feature/a”
这并不怎么优雅,至少在合并没有冲突的时候,这是一个空内容的Commit。
所以,替换的操作是:$ git fetch
$ git rebase origin/feature之后再push。
参考文档
by wxsmile