git基础

git
本质上是一个版本控制系统。
包括内容提交,历史记录,基于历史记录的回滚操作等,同时通过远程仓库实现协同开发。

两种版本控制系统
中央式:
只有一个远程仓库,必须不断提交或拉取远程仓库代码。典型的如svn
分布式:
除了远程仓库外,团队成员的机器山都有一份本地仓库,可以再本机器山提交代码,查看版本,切换分支等。典型的如Git。

Git的4区1堆和5态
参考:http://www.mamicode.com/info-detail-2428030.html
四个区:
工作区 :开发人员开发时直接操作的区域
暂存区 :执行Git add,已修改的代码从工作区进入暂存区
本地仓库:执行Git commit后,已修改的代码存暂存区进入本地仓库
远程仓库:执行Git push后,已修改的代码从本地仓库进入远程仓库

1堆 :
假设你正在开发一个功能f1,突然来了个更急的需求f2,现在这个功能的代码仅仅开发了一半,此时不完整且没测试,不能commit,但是这个代码又确实有用,这个时候就可以把代码放到堆中。
Git stash,自动把工作区当前的修改放到堆上。对应名称是上次 commit的信息

Git stash save "message"
假设紧急需求f2开发完毕了,现在继续开发f1。
Git unstash pop

git stash pop stash@{$num} ,比如应用并删除最新的stash:git stash pop stash@{0}

五个状态:
未修改(Origin)
已修改(Modified)&未追踪(Untracked)
已暂存(Staged)
已提交(Committed)
已推送(Pushed)

顺序操作
第零步:工作区与暂存区、本地仓库、远程保持一致
第一步:文件增删改,变为已修改状态,工作区与别的区不一致。
第二步:git add ,变为已暂存状态
$ git add --all # 当前项目下的所有更改
$ git add . # 当前目录下的所有更改
$ git add xx/xx.py xx/xx2.py # 添加某几个文件
第三步:git commit,变为已提交状态,此时修改到了本地分支
$ git commit -m"<这里写commit的描述>"
第四步:git push,变为已推送状态,此时修改提交到了远程分支
$ git push -u origin master # 第一次需要关联上
$ git push # 之后再推送就不用指明应该推送的远程分支了
$ git branch # 可以查看本地仓库的分支
$ git branch -a # 可以查看本地仓库和本地远程仓库(远程仓库的本地镜像)的所有分支

撤销操作
已修改,但未暂存
$ git diff # 列出所有的修改,检查工作区与暂存区的差异
$ git diff xx/xx.py xx/xx2.py # 列出某(几)个文件的修改

$ git checkout # 撤销项目下所有的修改
$ git checkout . # 撤销当前文件夹下所有的修改
$ git checkout xx/xx.py xx/xx2.py # 撤销某几个文件的修改
$ git clean -f # untracked状态,撤销新增的文件
$ git clean -df # untracked状态,撤销新增的文件和文件夹

已暂存,未提交
这个时候已经执行过git add,但未执行git commit,但是用git diff已经看不到任何修改。
因为git diff检查的是工作区与暂存区之间的差异。
$ git diff --cached # 这个命令显示暂存区和本地仓库的差异

$ git reset # 暂存区的修改恢复到工作区
$ git reset --soft # 与git reset等价,回到已修改状态,修改的内容仍然在工作区中
$ git reset --hard # 回到未修改状态,清空暂存区和工作区
说明:git reset --hard 操作等价于 git reset 和 git checkout 2步操作
注意:此时 Git reset后不需要加 head^等

已提交,未推送
执行完commit之后,会在仓库中生成一个版本号(hash值),标志这次提交。之后任何时候,都可以借助这个hash值回退到这次提交。
$ git diff <branch-name1> <branch-name2> # 比较2个分支之间的差异
$ git diff master origin/master # 查看本地仓库与本地远程仓库的差异

$ git reset --hard origin/master # 回退与本地远程仓库一致
$ git reset --hard HEAD^ # 回退到本地仓库上一个版本
$ git reset --hard <hash code> # 回退到任意版本
$ git reset --soft HEAD^ # 回退且回到已修改状态,修改仍保留在工作区中。
注意:此时后面一定要加head^等
HEAD^ 表示上一次的commit,也可以写成HEAD~1
如果撤回两次之前的,可以使用HEAD^^或者HEAD~2

已推送到远程
$ git reset --hard <版本号> #先在本地分支做回退
$ git push -f orgin master # 强制覆盖远程分支
$ git push -f # 如果之前已经用 -u 关联过,则可省略分支名
慎用,一般情况下,本地分支比远程要新,所以可以直接推送到远程,但有时推送到远程后发现有问题,进行了版本回退,旧版本或者分叉版本推送到远程,需要添加 -f参数,表示强制覆盖。
参考:http://www.mamicode.com/info-detail-2428030.html


Git为什么需要暂存区?
Commit操作是将暂存区的内容全部提交,所以我们要回到暂存区中思考;从工作区到暂存区,使用Git Add 文件名,我们可以选择性地向暂存区添加内容,然后将其分批提交,暂存区的意义是它将你准备提交的内容分批整体处理;


多分支合并的操作
场景:将branch1中的修改合并到branch3中
1)拉取更新提交法
本地分支切换到branch3: git checkout branch3
保证本地branch3是最新的:git pull
将branch1的修改拉到本地brnahc3:git pull origin branch1
注意此过程可能存在冲突,那么需要修改和处理所有的冲突文件 ,然后执行 git add -u和git commit -m "message"提交。
注意:此时你的本地仓储中的branch3就是合并后的代码了
将brnach3的修改推到远程仓库:git push

2)merge
切到brnach1:git checkout branch1
将远程branch1中的更新拉到本地:git pull origin branch1
本地切到branch3:git checkout branch3

拉取最新代码 Git pull origin branch3
本地branhc1中已经commit的更新合并到本地branch3:git merge branch1
将本地最新的branch3提交到远程:git push

3)rebase
参考:https://blog.csdn.net/tanga842428/article/details/53155860 Git的rebase与reset
初始版本为master0,第一次提交后变成了master1;master1为起点,创建了另一个分支test。这个时候,我们分别对master分支、test分支作两次提交,此时版本库应该成了这个样子:
master0(初始化后的版本)
||
v
master1===test0==>test1===>test2
||
v
master2===>master3
那么。如果我要让test分支从test0到test2之间所有的改变都添加到master分支来,使得master分支包含test分支的所有修改。这个时候就要用到git rebase了。
切换到master分支,然后运行下面的命令:
git rebase test

rebase和merge方式对比
https://blog.csdn.net/aroundme/article/details/51223687

https://www.jianshu.com/p/dc367c8dca8e
merge和rebase本质对比:
现在我们有这样的两个分支,test和master,提交如下:
         D---E test
         /
A---B---C---F--- master
在master执行git merge test,然后会得到如下结果:
           D--------E ----    test
         /                   \
A---B---C---F----G--- master
merge操作会生成一个新的节点G,G是基于F快照增加了test中D和E提交的内容,之前的提交分开显示。如果merge过程中出现了冲突,需要你逐个解决,解决冲突后重新commit。


在master执行git rebase test,然后得到如下结果:

           D--------E ----    test
         /                   
A---B---D---E---C‘---F’---  master
而rebase操作不会生成新的节点,是将两个分支融合成一个线性的提交。过程如下:
1)获取test的新commit:首先会切换到test分支,从E开始向前查找,直到找到和master分支最近的一个相同commit快照,会找到B,然后B-E之间所有commit生成patch文件。同时取消test分支中的提交记录。
2)自动切换分支到master,获取所有master上从B开始的新提交,也声称patch文件。

3)将1)中得到的patch文件应用到master分支。这一步不会产生任何冲突。然后将2)中生成的patch文件应用到master。

注意这里因为是在master新生成的E快照上修改,而原本patch是基于B快照生成的,所以如果F和E中都修改了同一个文件,此时可能会有冲突,会中断rebase,同时会提示去解决冲突。
处理好了,可以运行git rebase –continue继续直到完成
如果你不想处理,你还是有两个选择,一个是放弃rebase过程(运行git rebase –abort),另一个是直接用test分支的取代当前分支的(git rebase –skip,慎用,这样会丢失原master分支内容)。

4) 维护master 的HEAD,移动到E’

rebase篡改历史的实际操作演示与验证。

rebase找回丢失内容的方法(未验证):https://www.jianshu.com/p/48c9644e4bb6 

想要更好的提交树,使用rebase操作会更好一点。这样可以线性的看到每一次提交,并且没有增加提交节点。Git rebase详解
https://blog.csdn.net/j3t9z7h/article/details/85241850
1 合并多次commit
最近有两次提交(commit),但是为了同一个功能,所以想在push之前合并两个commit为一个。
1)开始合并,执行:git rebase -i HEAD~2
然后会自动进入vi编辑器模式,示例如下,其上面是你多次commit的记录,下面是注释了的指令说明,如下:
pick 35a91b2a6 删除无效内容
pick 8b2334b79 删除无效内容2

# Rebase 13fb12f8c..8b2334b79 onto 13fb12f8c (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
说明:上面默认对所有的commit都是pick操作,实际我们需求应该是,第一个pick 别的squash即可合并。操作指令解释如下:
pick:保留该commit(缩写:p)
reword:保留该commit,但我需要修改该commit的注释(缩写:r)
edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)
squash:将该commit和前一个commit合并(缩写:s)
fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)
exec:执行shell命令(缩写:x)
drop:我要丢弃该commit(缩写:d)

所以讲上面两行修改为:
pick 35a91b2a6 删除无效内容
squash 8b2334b79 删除无效内容2

2).执行esc 和 wq 保存
如果保存的时候,碰到了这个错误:
error: cannot 'squash' without a previous commit,注意不要合并先前提交的东西,也就是已经提交远程分支的纪录。
如果你异常退出了 vi 窗口,不要紧张:git rebase --edit-todo
rebase这时候会一直处在这个编辑的模式里,我们可以回去继续编辑,修改完保存一下。
git rebase --conitnue 会进入commit对应注释的处理,就是可以修改你提交到本地仓库时的注释,
然后 退出就会自动提交
get rebase --abort 放弃rebase

3) 修改注释,上面第一次wq后会进入修改注释页面,如下:
# This is a combination of 2 commits.
# This is the 1st commit message:

删除无效内容

Change-Id: Ic231a4994fde2f61006ea9efc75f85b1d462f07c

# This is the commit message #1:

删除无效内容2

Change-Id: I11000e2bc266795651aff311fd5c71002f369843

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#

因为这里我们只需要一个commit注释,所以修改成下面内容:
# This is a combination of 2 commits.
# This is the 1st commit message:

删除无效内容

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Jul 7 08:56:39 2020 +0800
#
# interactive rebase in progress; onto 13fb12f8c
# Last commands done (2 commands done):
# pick 35a91b2a6 删除无效内容
# squash 8b2334b79 删除无效内容2
# No commands remaining.

最后wq保存注释即可。
4).查看结果,执行git log ,你会发现只有一个commit记录了


2 分支合并,上面已介绍。

 

3 为什么要慎用Git rebase,什么情况出问题???

现在我们有这样的两个分支,test和master,提交如下:
         D---E test
         /
A---B---C---F--- master
在master执行git rebase test,然后得到如下结果:

           D--------E ----    test
         /                   
A---B---D---E---C‘---F’--- master


你在rebase后会更改分支历史,即原master分支是B-C-F(使用该分支的别的同事的本地分支就是如此),而现在实际远程分支是 B-D-E-C'-F', 同事的的本地分支版本的历史与远端版本不同,且没有很好的解决方案。
详细见:https://blog.csdn.net/gtlbtnq9mr3/article/details/80222523


对比 Git pull/merge/rebase
git pull = git fetch + git merge FETCH_HEAD
git pull --rebase = git fetch + git rebase FETCH_HEAD
Git fetch做了什么?
git fetch是将远程主机的最新内容拉到本地分支,但是拉下来的最新内容没有到工作区中,所以你看不到。
git fetch 命令:
$ git fetch <远程主机名> //这个命令将某个远程主机的更新全部取回本地
如果只想取回特定分支的更新,可以指定分支名:
$ git fetch <远程主机名> <分支名> //注意之间有空格
最常见的命令如取回origin 主机的master 分支:
$ git fetch origin master

git pull
git fetch origin master //从远程主机的master分支拉取最新内容
git merge FETCH_HEAD //将拉取下来的最新内容合并到当前所在的分支中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值