git 使用心得

VCS

VCS(Version Control System - VCS)的意思是:开发团队中的每个人向中央仓库主动提交自己的改动和同步别人的改动,并在需要的时候查看和操作历史版本,这就是版本控制系统。 版本控制、主动提交、中央仓库这三个要素,共同构成了版本控制系统(VCS)的核心

DVCS

DVCS(分布式版本控制系统)和VCS的主要区别就是:DVCS 除了中央仓库之外,还有本地仓库。团队中每一个成员的机器上都有一份本地仓库,这个仓库里包含了所有的版本历史,或者换句话说,每个人在自己的机器上就可以提交代码、查看历史,而无需联网和中央仓库交互——当然,取而代之的,你需要和本地仓库交互。

VCS两个主要功能:保存版本历史、同步团队代码。

DVCS保存版本历史的工作转交到了每个团队成员的本地仓库中,中央仓库就只剩下了同步团队代码这一个主要任务。它的中央仓库依然也保存了历史版本,但这份历史版本更多的是作为团队间的同步中转站。

git最简单的工作模型

Git 的最基本的工作模型:

  1. 从 GitHub 把中央仓库 clone 到本地(使用命令: git clone)
  2. 把写完的代码提交(先用 git add 文件名 把文件添加到暂存区(.git中index),再用 git commit 提交)
    • 在这个过程中,可以使用 git status 来随时查看工作目录的状态
    • 每个文件有 "changed/unstaged"(已修改),"staged"(已修改并暂存),"commited"(已提交三种状态,以及一种特殊状态 "untracked"(未跟踪)
  3. 提交一次或多次之后,把本地提交 push 到中央仓库(git push)

git发生冲突

如果同时做事,就会发生冲突:当一个人先于另一个人push代码(这种情况必然会发生),那么后push 的这个人就会由于中央仓库上含有本地没有的提交而导致push失败。

为什么会失败?

因为 Gitpush 其实是用本地仓库的 commits 记录去覆盖远端仓库的 commits 记录.(注:这是简化概念后的说法,push 的实质和这个说法略有不同),而如果在远端仓库含有本地没有的 commits 的时候,push (如果成功)将会导致远端的 commits 被擦掉。这种结果当然是不可行的,因此 Git 会在 push 的时候进行检查,如果出现这样的情况,push 就会失败。

branch 的创建、切换和删除

创建 branch

如果你想在某处创建 branch ,只需要输入一行 git branch 名称。例如你现在在 master 上:

你想在这个 commit 处创建一个叫做 "feature1" 的 branch,只要输入:

git branch feature1
复制代码

你的 branch 就创建好了:

切换 branch

不过新建的 branch 并不会自动切换,你的 HEAD 在这时依然是指向 master 的。你需要用 checkout 来主动切换到你的新 branch 去:

git checkout feature1
复制代码

然后 HEAD 就会指向新建的 branch 了:

除此之外,你还可以用 git checkout -b 名称 来把上面两步操作合并执行。这行代码可以帮你用指定的名称创建 branch 后,再直接切换过去。还以 feature1 为例的话,就是:

git checkout -b feature1
复制代码

在切换到新的 branch 后,再次 commit 时 HEAD 就会带着新的 branch 移动了:

而这个时候,如果你再切换到 master 去 commit,就会真正地出现分叉了:

git checkout master
...
git commit
复制代码

push的本质

实质上,push 做的事是:把当前 branch 的位置(即它指向哪个 commit)上传到远端仓库,并把它的路径上的 commits 一并上传。

总结一下关键点:

  1. push 是把当前的分支上传到远程仓库,并把这个 branch 的路径上的所有 commits 也一并上传。
  2. push 的时候,如果当前分支是一个本地创建的分支,需要指定远程仓库名和分支名,用 git push origin branch_name 的格式,而不能只用 git push;或者可以通过 git config 修改 push.default 来改变 push 时的行为逻辑。
  3. push 的时候之后上传当前分支,并不会上传 HEAD;远程仓库的 HEAD 是永远指向默认分支(即 master)的。

git add

git add的是改版的内容,而不是文件

比如你第一次改了a.txt,然后git add a.txt,git status发现a.txt已经在暂存区了,然后第二次修改了a.txt,再次使用git status,会发现a.txt既在暂存区,又在Changes not staged for commit

改了什么

-p 是 --patch 的缩写,通过 -p 参数,你可以看到具体每个 commit 的改动细节:

git log -p
复制代码

如果你只想大致看一下改动内容,但并不想深入每一行的细节(例如你想回顾一下自己是在哪个 commit 中修改了 games.txt 文件),那么可以把选项换成 --stat。

git log --stat
复制代码

show 查看具体的 commit 当前HEAD的提交

git show 【SHA-1】
复制代码

查看未提交的内容:diff

  1. 查看暂存区和上一条 commit 的区别:git diff --staged(或 --cached)
  2. 查看工作目录和暂存区的区别:git diff 不加选项参数
  3. 查看工作目录和上一条 commit 的区别:git diff HEAD

rebase

rebase 操作

## 如果要合并branch1到dev上
git checkout branch1 ## 先切换到branch1
git rebase master ##对master进行rebase
git checkout master ## 再切回master
git merge branch1 ## 在对branch1进行merge
复制代码

amend 刚刚提交的代码,发现写错了怎么办?

应用场景:针对于上一个commit在暂存区,并没有push到中央仓库

## 把错误改过来,重新提交即可
git commit --amend
复制代码

但是如果已经push,再用上面的命令,就会触发一次合并,因为--amend会建立一个新分支

commit --amend 并不是直接修改原 commit 的内容,而是生成一条新的 commit。

rebase -i:交互式 rebase

commit --amend 可以修复最新 commit 的错误,但如果是倒数第二个 commit 写错了,怎么办?

如果不是最新的 commit 写错,就不能用 commit --amend 来修复了,而是要用 rebase。不过需要给 rebase 也加一个参数:-i。

rebase -i 是 rebase --interactive 的缩写形式,意为「交互式 rebase」。

所谓「交互式 rebase」,就是在rebase的操作执行之前,你可以指定要rebase的commit 链中的每一个 commit 是否需要进一步修改。

那么你就可以利用这个特点,进行一次「原地 rebase」。

还是适用于没push的 链接如下

reset

reset --hard 丢弃最新的提交

# 这个就比较简单了
git reset --hard HEAD^
复制代码

注意:还是在没push的时候才能操作的

想丢弃的也不是最新的提交?

用交互式 rebase 撤销提交 这个命令其实上面说过,进入编辑页面,把某一个pick直接删掉就行了

git rebase -i HEAD^^
复制代码

注意:只能是在没push的时候操作 文章地址

代码已经 push 上去了才发现写错?

这才是真正有用的,因为如果在本地族暂存区的commit,其实都没啥大不了的,大不了丢弃就行了,如果push到了服务器,那就严重了

使用

git revert HEAD^
复制代码

把你上一条提交置反,然后在提交,这就是revert

reset

本节内容讲了 reset 指令的本质:重置 HEAD 以及它所指向的 branch 的位置。同时,介绍了 reset 的三种参数:

  1. --hard:重置位置的同时,清空工作目录的所有改动;
  2. --soft:重置位置的同时,保留工作目录和暂存区的内容,并把重置 HEAD 的位置所导致的新的文件差异放进暂存区。
  3. --mixed(默认):重置位置的同时,保留工作目录的内容,并清空暂存区。

checkout

checkout 并不止可以切换 branch。checkout 本质上的功能其实是:签出( checkout )指定的 commit。

git checkout branch名 的本质,其实是把 HEAD 指向指定的 branch,然后签出这个 branch 所对应的 commit 的工作目录。所以同样的,checkout的目标也可以不是 branch,而直接指定某个 commit:

checkout 和 reset 都可以切换HEAD的位置,它们除了有许多细节的差异外,最大的区别在于:reset 在移动 HEAD 时会带着它所指向的 branch 一起移动,而 checkout 不会。当你用 checkout 指向其他地方的时候,HEAD和 它所指向的 branch 就自动脱离了。

事实上,checkout 有一个专门用来只让 HEAD 和 branch 脱离而不移动 HEAD 的用法:

比如:git checkout dev (当前HEAD在feature/oppoos上面), 执行完了之后,HEAD就和dev指向同一个commit了 但是没有移动oppos的branch,只移动了HEAD。

reset会移动HEAD和branch两个的指向

stash

git stash 
git stash pop
复制代码

reflog

reflog 是 "reference log" 的缩写,使用它可以查看 Git 仓库中的引用的移动记录。如果不指定引用,它会显示 HEAD 的移动记录。假如你误删了 branch1 这个 branch,那么你可以查看一下 HEAD 的移动历史:

注意:不再被引用直接或间接指向的 commits 会在一定时间后被 Git 回收,所以使用 reflog 来找回删除的 branch 的操作一定要及时,不然有可能会由于 commit 被回收而再也找不回来。

tag

tag 是一个和 branch 非常相似的概念,它和 branch 最大的区别是:tag 不能移动。所以在很多团队中,tag 被用来在关键版本处打标记用。

转载于:https://juejin.im/post/5ab212f16fb9a028b547c41e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值