1. git提交分支相关
- 在本地新建分支,保证和远程分支一样
git checkout -b 分支名
如果分支已存在,只需要切换的话git checkout 分支名
- 提交前先把代码拉下来更新一下,确保不会覆盖别人的代码
git pull origin 远程分支
- (如果有)解决冲突
git diff // 然后查看冲突的原因
- 查看git状态(哪些还未提交)
git status
- 提交到缓存区
git add .
- 提交到本地仓库
git commit -m '我这次提交是为了干啥'
- 提交到远程仓库(线上仓库)
git push origin 分支名
- (如果不存在)本地建立一个你要合并的分支(如你在a分支上开发,现在要和b分支merge并提交到b分支上)
git checkout -b 要合并的分支b
- 把要合并分支的代码拉下来
git pull origin 要合并的分支b
- 在本地合并到b分支
git merge 要合并的分支b
- 如果报错,那么查看git状态
git status
2. 关于.gitigonore 文件详解
这个文件的完整文件名就是“.gitignore”,注意最前面有个“.”。这
一般来说每个Git项目中都需要一个“.gitignore”文件,这个文件的作用就是告诉Git哪些文件不需要添加到版本管理中。
实际项目中,很多文件都是不需要版本管理的,比如Python的.pyc文件和一些包含密码的配置文件等等。
这个文件的内容是一些规则,Git会根据这些规则来判断是否将文件添加到版本控制中。
过滤规则:
/mtk/ 过滤整个文件夹
*.zip 过滤所有.zip文件
/mtk/do.c 过滤某个具体文件
被过滤掉的文件在push的时候不会上传。
需要注意的是,gitignore还可以指定要将哪些文件添加到版本管理中:
!*.zip
!/mtk/one.txt
版本规则:
唯一的区别就是规则开头多了一个感叹号,Git会将满足这类规则的文件添加到版本管理中。
假如只需要管理/mtk/目录中的one.txt文件,这个目录中的其他文件都不需要管理。就需要使用这个!规则:
/mtk/
!/mtk/one.txt
如果在创建.gitignore文件之前就push了项目,那么即使你在.gitignore文件中写入新的过滤规则,这些规则也不会起作用,Git仍然会对所有文件进行版本管理。
出现这种问题的原因就是Git已经开始管理这些文件了,所以你无法再通过过滤规则过滤它们。
重点:在项目开始就创建.gitignore文件的习惯,否则一旦push,处理起来会非常麻烦。
3. git的版本回退
因为在合并分支的过程中,变更太多,是本地环境配置的问题,需要回退到上一个版本,然后再重新提交。
git log
- 定义:该命令显示从最近到最远的提交日志。每一次提交都有对应的 commit id和 commit message。
```
git log --pretty=oneline
- 可以将版本号和描述内容在一行内显示,使得输出更加简洁一些
![image-20220501172550786](https://s2.loli.net/2022/05/01/vZd5cjHiU6Cs2Eb.png)
git reset --hard id
- 定义:根据 id 回退到指定的版本,一般要回退的版本号的前7位即可
git push origin HEAD --force
- 推送到本地到远程仓库:让远程仓库代码你本地一样,到当前本地的版本。
git reflog
- 定义:查看命令操作的历史查找到需要的 ***操作id***,依旧使用```*git reset --hard id*```可以回退到先前的版本。
## 4. git的cherry-pick
cherry-pick 的翻译是择优挑选,使用git cherry-pick命令,可以选择将现有的一个或者多个提交的修改引入当前内容。
那么,什么情况下会有到这么不常见的命令呢?
假设你现在正在开发一个项目,有一个功能分支 feature,开发分支 develop。 feature 有3个提交,分别是 A ,B ,C 。develop 分支只想加入 C 功能, 此时合并操作无法满足,因为直接合并 feature,会将3个提交都合并上,我想合并就只有 C,不要 A,B。此时就需要挑樱桃大法–cherry pick!
具体的做法:
1.切换到 develop 分支。
2.通过 git log feature,找到 C 的 SHA1 值。
3.通过 git cherry-pick <C的SHA1> ,将 C 的修改内容合并到当前内容分支 develop 中。
4.若无冲突,过程就已经完成了。如果有冲突,按正常冲突解决流程即可。
![image-20220501172636309](https://s2.loli.net/2022/05/01/mQ3jtNH8P7Ak5SV.png)
从上面简单的小例子上看,我想,小伙伴们,都应该已经对 merge 和 cherry-pick 有了大概的区分,这里做下对比,让大家有个清晰明确的掌握,防止似是而非,以后误操作。
> git merge :将两个提交历史合并。
> git cherry-pick:将提交对应的内容合并。
这里,非常需要明确的一点,**commit 代表的是修改!**
例中,提交 C 的内容,就是对比 B 上面做的修改,可能是创建了一个文件,或者修改了一个词语。那么 C 内容就是一个文件的添加,和一个词语的修改。
以提交 C 为结束点的提交历史,实际内容是提交 C 和 C 之前所有的修改。
**cherry-pick 操作的对象就是 commit。**
**merge 操作的对象就是 commit history。**
例子:
利用cherry-pick,可以将一个分支中的修改的内容合并到另一个分支上。如要将lyrisgao中的某一个功能提交的内容合并到addsomeparms
![image-20220501172713045](https://s2.loli.net/2022/05/01/9zJs6aE5ko3TVrZ.png)
- 合并之后,可以发现 提交的并不是真正的分支的内容,是分支内容的复制品,因为两者的SHA1的值是不同的,可以确定是两个提交。![image-20220501172726737](https://s2.loli.net/2022/05/01/UyiVFRoCvzhGn3a.png)
## 4.1 cherry-pick 其他常用命令
- 挑选多个提交合并,提交之间用空格相隔。例如,想挑选1号和3号的,就可以用git cherry-pick 4d2951 e4cdff9命令一步到位了。
git cherry-pick <commits>
- 挑选一个范围的多个提交合并,但是这个语法对应操作区别是左开右闭,不包含start-commit。另外要注意两个commit 之间要求有连续关系的,并且前者要在后者之前,顺序不能颠倒。
git cherry-pick <start-commit>..<end-commit>
- 这个和上面一样,区别就是加了一个^符号,就变成闭区间了,包含 start-commit。
git cherry-pick <start-commit>^..<end-commit>
- 挑选 branch 最顶端的提交。例如挑选 3 号樱桃可以用git cherry-pick develop。```git cherry-pick <branch name>``````git cherry-pick --continue //继续下个操作git cherry-pick --quit //退出git cherry-pick --abort //停止本次操作```以上是关于 cherry-pick 操作控制命令,当 cherry-pick 多个提交时,假设遇到冲突,–continue继续进行下个,–quit结束 cherry-pick 操作,但是不会影响冲突之前多个提交中已经成功的,–abort直接打回原形,回到 cherry-pick 前的状态,包括多个提交中已经成功的。
## 5. git merge 和 git rebase
**git rebase 和 git merge是git合并分支的两种方式,然而他们却采用了不同的工作方式**,以下面的一个工作场景说明其区别:
![image-20220501172807189](https://s2.loli.net/2022/05/01/2Zcd1sqomQjh3ea.png)
场景:
> 下图所示:当feature分支有新的需求提交,同时,master 分支也有修改。
这时,如果要将master 上新的提交合并到你的feature分支上,我们有两种选择:merging or rebasing
## 5.1 merge
执行以下命令:
git checkout feature
git merge master
或者执行:
git merge master feature
此时在feature上git 自动会产生一个新的commit(merge commit)
> **注意:**
git 本地分支合并master分支代码 : 提示为 git merge Already up-to-date.
原因在于merge之前,master分支的代码不是最新代码
做法:
1.应该先切换到master分支
git checkout master
2.拉取代码
git pull origin master
3.再切换到要合并master的分支
git checkout 分支
4.合并代码
git merge master
有冲突则解决冲突
当使用 git log 查看时,发现已经多了一个commit
![image-20220501172841032](https://img-blog.csdnimg.cn/img_convert/e416ac4532391c191554517fad8d98eb.png)
## 5.2 merge 特点
merge 特点:自动创建一个新的commit
当合并时遇到冲突,修改后重新commit即可
优点:将commit的实际情况进行记录,便于以后查看
缺点:由于每次merge会自动产生一个merge commit,所以在使用一些git 的GUI tools,如果commit频繁,这样会使得feature分支很杂乱,这时可以考虑使用rebase来进行合并处理。
## 5.3 rebase
本质是变基,即找公共祖先
执行以下命令:
git checkout feature
git rebase master
![image-20220501172907076](https://s2.loli.net/2022/05/01/rZSi1vRmCJz2ghk.png)
## 5.4 rebase 特点
rebase 特点:将commit历史进行合并
优点:项目历史比较简单,少了merge commit
缺点:当发生冲突时不容易定位问题,因为re-write了history
合并时如果出现冲突需要按照如下步骤解决
1.修改冲突部分
2.git add3. git rebase --continue
(如果第三步无效可以执行 git rebase --skip)
4.不要在git add 之后习惯性的执行 git commit命令
The Golden Rule of Rebasing rebase 的黄金法则
never use it on public branches(不要在公共分支上使用)
比如说如下场景:如图所示
![image-20220501172920139](https://s2.loli.net/2022/05/01/NJSagP6HsyoGATp.png)
如果你rebase master 到你的feature分支:
rebase 将所有master的commit移动到你的feature 的顶端。问题是:其他人还在original master上开发,由于你使用了rebase移动了master,git 会认为你的主分支的历史与其他人的有分歧,会产生冲突。
所以在执行git rebase 之前 需要认真考虑,
会有其他人看这个分支么?
if YES 不要采用这种带有破坏性的修改commit 历史的rebase命令
if NO ok,随你便,可以使用rebase
### 将几个commit log 合并一个
git rebase -i 版本号(需要合并的那几个commit log 之前的那一个commit版本号)
```
- 之后会显示以下界面pick : 代表合并后的提交用这个提交的注释; s : squash命令的简写,代表合并提交中包含这个提交; d : 代表合并提交中排除这个提交。
- wq保存之后
git rebase --continue
- 设置注释之后
- 完成以上是将连续的commit id合并,假如是不连续的话,那么你也是拿最早的commit id来执行git rebase -i commit id,然后进入弹出框,你会看到pick中没有最早你要合并的那个commitid,这里你需要按照列表的格式把最早的commit id复制到顶部,格式就是 pick commit id XXX,这个XXX就表示注释(可有可无),然后再把你要合并的几个commit一定复制到当前这个新加的pick下面,然后修改成 (s commit id XXXX),有几个写几个,把重复的去掉,然后保存即可。
5.5 总结
尽量不要在公共分支使用 rebase
本地和远端对应同一条分支,优先使用 rebase ,而不是 merge
因为往后放的这些 commit 都是新的,这样其他从这个公共分支拉出去的人,都需要再 rebase,相当于你 rebase 东西进来,就都是新的 commit 了
1-2-3 是现在的分支状态
这个时候从原来的 master , checkout 出来一个 prod 分支
然后 master 提交了4.5,prod 提交了6.7
这个时候 master 分支状态就是1-2-3-4-5,prod 状态变成1-2-3-6-7
如果在 prod 上用 rebase master , prod 分支状态就成了1-2-3-4-5-6-7
如果是 merge
1-2-3-6-7-8
… |4-5|
会出来一个8,这个8的提交就是把4-5合进来的提交
merge 和 rebase 实际上只是用的场景不一样
更通俗的解释一波:
- 比如 rebase,你自己开发分支一直在做,然后某一天,你想把主线的修改合到你的分支上,做一次集成,这种情况就用 rebase 比较好。把你的提交都放在主线修改的头上。
- 如果用 merge,脑袋上顶着一笔 merge 的8,你如果想回退你分支上的某个提交就很麻烦,还有一个重要的问题, rebase 的话,本来我的分支是从3拉出来的, rebase 完了之后,就不知道我当时是从哪儿拉出来的我的开发分支
- 同样的,如果你在主分支上用 rebase , rebase 其他分支的修改,是不是要是别人想看主分支上有什么历史,他看到的就不是完整的历史课,这个历史已经被你篡改了
结论:
想要干净的历史,少了merge commit的线性历史树,选择git rebase
而如果你想保留历史记录,并且想要避免重写commit history的风险,使用git merge
版权归原作者 几窗花鸢 所有, 如有侵权,请联系我们删除。