Git笔记-从入门到放弃

316 阅读4分钟

写在前面

自己原来一直在用IDEA提供的Git管理,但是有时候会遇到解决不了和理解不了的问题,所以觉得还是需要系统学习一下Git。

1. 安装Git

安装命令

$ sudo apt-get install git

安装完成后,需要配置全局用户名和邮箱

$ git config --global user.name "my name"
$ git config --global user.email "my email"

2. 创建仓库

创建仓库

$ git init

这样会创建一个空仓库,生成.git目录,.git目录是仓库管理目录

提交

$ git add [filename]

将文件添加进暂存区,接受Git管理

$ git commit -m "这次的提交说明"

将暂存区的修改提交到版本库中的分支

$ git commit -am "提交说明"

将工作区和暂存区的所有修改都提交到分支,这种方式不能指定具体文件

注意,每次对工作区有了新的修改,都要先执行git add [filename]将修改存入暂存区,Git才可以管理这次的修改

3. 版本控制

查看当前Git的状态

$ git status

对于还未提交的修改,可以对比当前的修改和最新的版本库

$ git diff [filename]

3.1 版本回退

查看当前分支

$ git log

reset

重置HEAD指针:

$ git reset --hard HEAD^

HEAD^代表回退一个版本,如果想回退两个版本,需要HEAD^^,依次类推,或者可以HEAD~100指定回退100个版本。这种方式是以当前HEAD指针为参考,指定要回退几个版本,也可以不参考HEAD指针,直接重置HEAD指针到某个版本:

$ git reset --hard [版本号]

这种直接指定具体版本重置HEAD指针的方式非常好用,不仅可以向前回退,也可以向后回退。但是向后回退需要知道版本号,git log命令无法知道后面的版本号。但是既然当前版本存在更后的版本,那么肯定是执行过重置HEAD指针的操作的,我们可以先查看当前版本库执行过的所有操作:

$ git reflog

这样可以得到版本库的操作链,这条操作链不仅包括提交等记录,还包括每一次重置HEAD指针的操作,会比较复杂。如果需要理清版本库操作,可以先重置HEAD到最新的commit版本,然后用git log就可以得到版本库的所有版本,再结合git reflog就可以理清所有操作。

soft hard mixed merge keep

git reset后面可以跟四种参数,分别表示这次reset操作对工作区和暂存区的影响

--soft: 不改变工作区和暂存区

--hard: 改变工作区和暂存区,意味着工作内容丢失

--mixed: 改变暂存区,不改变工作区,这是默认参数

--merge: 基本和--hard,但会保留一些修改,不常用

--keep: 基本和--hard类似,不同的地方是,如果reset过程中和当前工作区有冲突,则停止reset,不常用

revert

用法:

$ git revert HEAD^
$ git revert [commit_id]

基本和reset一样,但是revert操作会新生成一个commit,用来抵消之前的某个commit

3.2 工作区,暂存区和版本库

下图显示了Git的基本空间划分,主要分为工作区和版本库。工作区就是当前修改在的地方,体现在仓库中就是.git目录之外的地方。.git目录就是Git版本库,而版本库又包含暂存区和具体分支。暂存区就是.git目录下的index文件,所以暂存区称为index或者stage。凡是没有进入暂存区的修改,都不会被Git跟踪和管理。

IDEA自带的Git管理总给人感觉工作区和暂存区合二为一了,我们只需要做出修改后执行git commit提交到分支上,但是其实标准Git流程是需要先git add把修改移入暂存区,然后才可以git commit提交到分支。暂存区的存在更有利于版本控制,但是增加了我们使用Git的复杂度。IDEA简化了这样的操作,但是有时候出了问题还是需要知道Git的原理并用命令行解决。如果需要查看内容和解决冲突这样的操作,还是IDEA好用,毕竟提供了很好的界面,但是如果是Git管理流程出了问题,最好还是使用Git命令行解决。

图中的各种命令其实就是在工作区,暂存区和分支之间转移和同步修改。

Git工作区版本库

git add命令会把工作区的修改移入暂存区,如果是删除文件,需要git rm把删除文件这个修改移入暂存区

git commit: 会把暂存区的修改提交到分支上

git commit -a: 把工作区和暂存区的所有修改一起提交到分支上

git checkout -- [filename]: 把工作区的内容同步成暂存区的内容

git reset HEAD [filename]: 把暂存区同步成和分支的内容一样,工作区不受影响

git rm --cached [filename]: 删除暂存区文件,不影响工作区

git checkout -- [filename]: 把工作区的内容同步成暂存区的内容

git checkout HEAD [filename]: 把HEAD指向的分支内容同步到工作区和暂存区

以上的同步操作都会把修改丢失,比较危险,而且三个区域之间操作很复杂,比较难记。

我个人的总结方案是只要记住基本的git addgit commit,另外还有git rm --cached [filename]比较实用。

git rm --cached [filename]主要是在.gitignore中添加新的文件,但是这个文件又已经被跟踪的时候,就可以用这个方法把文件从暂存区删除,也就是取消跟踪文件。

如果有修改不想提交又不想丢失,最好使用栈先保存下来。

3.3 栈

凡是想要暂时保存的修改,都可以使用Git栈暂时保存。

保存栈

$ git stash save "这次保存的说明"

这样会把工作区和暂存区的修改都保存到栈中,这不是复制,这是剪切,工作区和暂存区都被还原了

查看栈

$ git stash list

栈还原

$ git stash pop

栈顶节点还原到工作区

$ git stash pop --index

把栈顶节点还原到工作区和暂存区

$ git stash pop stash@{1}

还原指定节点到工作区,这个节点号可以通过git stash list得到

如果两个栈节点有冲突,想先后被还原这两个节点并解决冲突,需要把第一个节点还原到暂存区,再还原第二个节点,否则还原第二个节点会失败。其实这很好理解,在暂存区才能接受Git管理,冲突解决也是管理的一种。

上面的命令都会删除节点,把pop改成apply就不会删除节点

删除栈

$ git stash drop stash@{1}

删除stash@{1}这个节点,如果不指定节点,则删除栈顶节点

$ git stash clear

删除栈内所有节点

删除栈节点都要慎重,因为不会还原到工作区

4. 远程仓库

添加和查看远程仓库

$ git remote add origin [git_address]

添加一个名为origin的远程仓库关联,一个本地仓库可以和多个远程仓库关联

$ git remote -v

查看本仓库关联的所有远程仓库

克隆仓库

$ git clone [git_address]

拉取

$ git fetch origin/matser

更新本地的远程origin仓库的master分支副本,不指定分支则更新整个仓库

$ git pull origin master:test

把远程origin仓库的master分支更新并合并到本地test分支上

合并

$ git merge origin/master

把本地的origin/master副本合并到当前分支

提交

$ git push -u origin master

将本地仓库当前分支推送到origin的master分支上 -u参数的意思是把关联origin地址的master分支,以后可以简化拉取和推送命令

$ git push origin test:master

把本地的test分支推送到远程origin仓库的master分支上

这张图可以帮助理解仓库之间的关系和操作

Git原理图

5. 分支管理

Git的分支管理速度非常快,因为一般只涉及到指针的创建和移动。

创建分支

$ git branch dev

创建dev分支

切换分支

$ git checkout dev

切换到dev分支,如果dev分支不存在,需要创建并切换,则如下

$ git checkout -b dev

git checkout本身还有把暂存区内容向工作区同步的作用,为了避免混淆,高版本的Git可以这样切换分支

$ git switch dev
$ git switch -c dev

意思分别是切换到dev分支,创建并切换到dev分支

查看分支

$ git branch

合并分支

$ git checkout master
$ git merge dev

把dev分支合并到master分支,需要先切换到master分支,再执行git merge dev

这样执行的是Fast forward模式,这个模式在合并分支的时候不会创建新节点,最好禁用Fast forward模式,如下

$ git merge --no-ff -m "合并分支说明" dev

这样会创建一个新节点,从日志上方便查看

合并分支可能会有冲突要解决,涉及到冲突解决最好使用IDEA的Git管理,所以合并分支最好也用IDEA

删除分支

$ git branch -d dev

删除dev分支

如果dev分支从来没被合并过,上面的命令会报错,要使用下面的命令强制删除

$ git branch -D dev

这样会强制删除dev分支

解决冲突

解决冲突最好使用IDEA的冲突解决,比较方便

Rebase

用法:

$ git rebase

rebase操作会把不同人的commit尽量合并到一个主干上,让提交记录比较好看,有冲突的commit需要merge,不能变成一条线

合并commit

$ git rebase -i [start_commint_id] [end_commit_id]

start_commint_idend_commit_id进行commit合并,end_commit_id必须写,start_commint_id如果不写,则默认从HEAD开始,这是个左闭右开的区间

$ git rebase -i HEAD~3

HEADHEAD~1HEAD~2进行合并

$ git rebase -i 36224db

36224db之前的所有commit合并,不包括36224db

cherry-pick

假如现在有master和dev分支,我们不想把dev分支合并过来,只是想把其中的某个commit合并到master上,就需要用到cherry-pick,用法:

$ git checkout master
$ git cherry-pick [commit_id]

6. 标签管理

标签(tag)其实就是commit的一个别名,只不过commit的唯一ID是一串难记的哈希值,所以用标签来简化记忆,并且默认带标签的都是有版本意义的,所以标签也不是可以随便加的

如果一个加了tag的commit出现在多个分支上,那么所有分支都可以看见这个tag

创建标签

$ git tag v1.0

给当前分支的当前commit加上v1.0的tag

$ git tag v1.0 f52c633

f52c633这个commit加上v1.0的tag

$ git tag -a v1.0 -m "标签的说明"

给v1.0标签加上说明

删除标签

要想修改标签的内容,只能先删除,再重新打标签

$ git tag -d v1.0

删除v1.0这个tag

$ git push origin :refs/tags/v1.0

删除远程origin的v1.0标签,其实就是推送一个空的东西代替refs/tags/v1.0

推送标签到远程仓库

$ git push origin v1.0

把v1.0推送到origin

$ git push --tags

一次性把所有标签推送到origin

查看标签

$ git tag

查看当前分支的所有tag

$ git show v1.0

查看v1.0这个tag的具体信息

参考