常用Git命令和理解

152 阅读7分钟

Git 学习

[toc]

luke的git手册

Git基本概念图

git对象学习

四种对象

blob

  1. 文件名为sha-1算法和内容hash得到的

tree

  1. tree对象类似目录这么一个概念,主要记录下属的blob和tree对象。
  2. tree本身的文件名也是sha-1的哈希值。
  3. Git 根据某一时刻暂存区(即 index 区域)所表示的状态创建并记录一个对应的树对象,

commit

  1. commit记录的是一条commit信息,是和git commit 对应的。

  2. commit链接一个tree对象。

  3. commit有一个parent属性,用来将一个分支串起来。

tag

我们都知道,对一个分支来说。会一直向前走。但是有时候我们在分支上需要一个固定的坐标。就可以使用tag。

当然也可以通过移动Head指针,指向对应的Commit Id,只不过tag做了一个类似alias的功能

一个基本的流程串联

脑子里有颗树

这里是git的最底层原理,用来理解其怎么实现,但最重要的开始理解文章最开始的Git基本概念图。

git init
echo "ver1" > file.txt
git add file.txt
git status

Changes to be committed:
new file: file

暂存区新加文件file

git commit -m "first commit"

git commit 根据暂存区文件生成一个tree对象,并用commit链接tree对象。

此时的逻辑图是这样的

echo "ver2" >> file
echo "new" > new
git add file
git add new
git commit -m "second commit"

此时的逻辑图是这样的

git rm new
git commit -m "third commit"

获取和创建Git仓库

本地工作流

git add/rm

git status

git commit

git reset

git restore

git add / rm / restore

git add

git add <file> 将文件提交到暂存区

一旦文件git add后,就相当于被track了,任何对文件的改动都会被git所记录。

git restore

git restore --staged <place> 从HEAD中恢复文件到暂存区

git restore <place> 将文件从暂存区恢复到工作区

git restore --source <branch>:<place> 从其他的commit恢复文件

这里的<place> 可以是file,也可以是正则之类的东西

测验

git init
echo "123" > file
git add file
rm file

如何将file恢复。

git restore file

git commit -m "ver1"
echo "error" > file
git add file
rm file

如何恢复commit中的file

git restore --staged file git restore file

如何恢复内容是“error”的file

git restore file

git commit / reset

git commit 用来将暂存区的文件提交到本地数据库中。

git commit --ammend

会取消上一次的commit,并合并你暂存区的文件,重新提交一次commit

  1. 主要被用来fix上次commit忘记提交的一些细节。
  2. 仅仅在自己的commit后使用,因为--ammend会撤销上一次的commit。所以对公共的commit使用会影响别人。
git reset 用来回退版本

git reset HEAD

git reset --soft <verID>

git reset --mixed <verID> 默认

git reset --hard <verID>



git reset HEAD 默认使用–soft。

reset

reset --soft 本质就是移动了HEAD指针。

git reset HEAD 主要是用来回滚暂存区。

git reset HEAD

重置暂存区,主要用来roll back

git init
echo ver1 > file
git add file
git commit -m "ver1"

echo ver2 >> file
git add file

git reset HEAD

git reset 三种模式

echo ver1 > file.txt
git add file.txt
git commit -m "ver1"

echo ver2 >> file.txt
git add file.txt
git commit -m "ver2"

echo ver3 >> file.txt
git add file.txt
git commit -m "ver3"

git reset --soft

git reset --soft HEAD^

仅仅移动HEAD指针。workspace和staging area都不受影响。

git reset --mixed

git reset --mixed HEAD^ 

HEAD 指针移动,同时暂存区也会被回滚到ver2

git reset --hard

同时会撤销暂存区,workspace,和local repository。是一个非常危险的命令。

cherry-pick 和 git stash

cherry-pick

负责将某个commit-id的commit复制到当前分支上。

git stash

用来保存暂存区和工作区的文件内容

  1. git stash save "save message"。
  2. git stash apply stash@{num} 应用第几个存储。
  3. git stash list 来列举哪些存储。

交互远程仓库

远程分支和本地分支

远程分支的本质上也是一个分支。其就是在本机中远程仓库对应分支的映射分支。

远程分支的名字就是 <repo>/<local-branchname>,一般为origin/<local-branchname>。默认的远程仓库名就是origin。

git push

git push <remote> <place>



1. 将本地分支的所有commit提交到<remote>/<place>分支下,同时更新远程仓库中的对应分支。



git push <remote> <source>:<dest>

1. 同上,但是将本地分支commit提交到<remote>/<dest>分支下,同时更新远程仓库的<dest>分支。



git push <remote>  :<dest> 可以删除远程分支

git fetch/pull

git fetch

会干俩件事

  • 从远程仓库下载本地仓库中缺失的提交记录。
  • 更新远程分支指针(如 origin/master)。
git fetch <repo> <place>

<repo> 远程仓库名

<place> 分支名
git fetch

会更新所有分支

git fetch origin foo

下载本地foo分支缺失的commit,然后更新origin/foo指针。

git pull

git pull就是在完成git fetch后,会用当前分支merge远程分支。

git merge/rebase

merge

git merge 可以分为两种情况。1. fast forward 2. 三路合并

fast forward

当前分支master和目标分支feature没有分叉。则可以直接进行fast forward合并。

三路合并

当在master分支,merge feature分支时。

  1. 去寻找common recent accestor,就是M3。如果期间feature分支同步过master,则会cra就会变化。
  2. 比较cra和当前分支diff1,cra和目标分支diff2。
  3. 如果俩个diff在同一位置发生改动,则冲突。否则,保留有改动的一方即可。

理解了这个原理后,如何快速造一个confict出来。

git init
echo "hello" > test.txt
git add test.txt
git commit -m "m1"
git switch -c feature
echo "world" >> test.txt
git commit -am "f1"
git switch master
echo "nihao" >> test.txt
git merge feature

rebase

Reapply commits on top of another base tip 这里的官方解释很明确

合并分支

git rebase <upstream> <branch>

1. 如果指定了branch,就会先执行git switch branch,然后执行git rebase
2. 如果没有指定<upstream> ,则默认以本分支的远程分支为upstream

流程

  1. 将本分支所有的commit,但是在upstream里没有的commit保存到临时区。
  2. 将分支指针移动到upstream,然后将临时区的所有commit依次apply。

合并commit

git rebase -i <commit-id>

  1. 改变commit顺序
  2. 合并多个commit,
    1. pick:保留该commit
    2. reword:保留该commit,但是要修改commit注释
    3. squash:将该commit和前一个commit合并
    4. drop:不要该commit

常见的使用场景

1. 准备开发feature

一般从master中checkout一个新的分支出来

git switch master
git pull master
git switch -c feature/${someone_name}/${feature_name}

2. 准备测试

一般测试时,是合到experiment分支上去的。 重新checkout一个feature的exp分支出来。

git switch experiment
git switch -c feature/${someone_name}/${feature_name}_exp
git merge feature/${someone_name}/${feature_name}

这么做的原因是因为万一experiment分支有了Bug代码,但不是你提交的。暂时修改不了,可以让自己的${feature_name}_exp作为测试分支。因为这个分支不会有别人的测试代码。

3. 准备合入master

  1. 合并commit成一个 git rebase -i
  2. git pull origin master 更新master分支
  3. git rebase origin/master ,当前分支rebase master分支
  4. git push origin 自己的分支名

4. git commit --ammend使用(新手不建议使用)

git commit -m "commit"
git push origin branch_name

这时候发现有个代码写错了,改动了一番后,想使用

git commit --ammend
这时候直接
git push -f origin branch_name

因为commit --ammend会重新生成一个commit id,和远程仓库不一致。

这里不建议新手使用是因为,如果已经把commit1提交到远程仓库,然后通过ammend再去修改,这时候需要push --force,所以只能对自己的分支这么搞,和别人合作时不可以。

犯错时用到的高级特性

  1. git revert 用来消除掉自己的一次commit,所以这里要求自己的commit每次最好是功能完备的。

通过找到一个commit id。 比如说 git revert -i 1e1f61f8125a1706c98a465287a5c22e15a4cc83

学习网站

git 算是日常开发中用到的非常重要的工具。建议熟练掌握。

建议完成里面所有的官卡。基本上就对git非常熟悉了。可以大胆地玩了。

learngitbranching.js.org/?locale=zh_…

参考资料

git-scm.com/book/zh/v2