玩转Git三剑客笔记

引言

整理了下之前极客时间上《玩转Git三剑客》的笔记,该课程适合入门级读者。
本文是笔记的第一部分,主要侧重 git 的操作;第二部分侧重的是团队协作。

09 .git 目录

  • HEAD文件:形如ref: refs/heads/master, 内容是引用,指向当前的分支;
  • CONFIG文件:本地配置信息,如用户名,邮箱;
  • refs 文件夹: 包含 heads (分支)和 tags (里程碑);
  • heads/master: 一串字符, commit id;
  • heads/tags: 类似上 heads/master;
  • objects 文件夹: 若干个两个字符命名的文件,加pack和info;两个字符的文件名加文件内容构成了一串哈希字符;
git config --list
git cat-file -t xxxx //  查看类型, commit, blob, tree 最常见
git cat-file -p xxxx //查看详细内容

10 commit-tree-blob 关系

commit对应一棵tree,是当时的项目快照。tree里可以包含多个tree和blob;
一个文件夹对应一棵tree,一个文件名对应一棵tree;

git cat-file -p  hashVal

11 tree

find ./directory -type f //

12 分离头指针 detached HEAD

git branch new_branch_name commitID
git diff commitid commitid^2

13 HEAD 和 Branch

牢记 git 中,一切都是指针。

  • master~N: master 的第 N 个父 commit;
  • master^N: master 的父 commit 中的第 N 个;

参见 What's the difference between HEAD^ and HEAD~ in Git?.

14 删除分支

git branch -d branch_name
git branch -D branch_name //删除没有merge的分支
git branch -av //显示本地和远端的所有分支

15~18 修改commit的message

修改最近一次的或某一次的

//还未提交到remote server的情况下
git commit --amend //最近一次

git rebase -i parentCommitId_of_toModifyCommitMsg //会弹出一个交互式的页面,需要修改 pick 为 reword

假设项目的有若干个commit: A-B-C-D, A为最新的commit,现在要
合并连续的N个commit为一个commit:合并ABC

git rebase -i D
//弹出vi界面中 编辑
pick A
squash B
s C

//保存后退出即可,此时会弹出和 执行 git commit 命令后相同的界面

合并不连续的N个commit为一个commit:合并 B和D

git rebase -i D
//弹出vi界面中 编辑
pick D
squash B
pick C
pick A

//保存后退出即可,此时会弹出和 执行 git commit 命令后相同的界面

19~20 比较工作区 暂存区和HEAD文件的差异

工作区 --> 暂存区 --> 库 HEAD

比较暂存区和 HEAD

git diff --staged 
git diff --cached //后面可加某个文件名

比较工作区和暂存区

git diff 
git diff -- fileName//后面可加若干个文件名 

比较工作区和 HEAD

git diff HEAD  //后面可加某个文件名 -- fileName

21~23 恢复更改

恢复暂存区内容为HEAD中内容

git reset HEAD
git reset HEAD -- fileName

恢复工作区内容为暂存区内容

git checkout -- fileName

24 消除最近的几次提交

有若干个提交: A->B->C->D->E(E最早的提交) 消除ABC提交:

git reset --hard D_hashid //将HEAD,暂存区,工作区都指向D

25 某个文件在某两次提交下的差异

有若干个提交: A->B->C->D->E

git diff B_hashid D_hashid // -- fileName 可加指定文件

26 移动删除文件

git rm 
git mv

27 git stash

git stash
git stash list

git stash pop // 等同于 stash@{0} , 内容恢复到工作区然后删除
git stash pop stash@{n} 

git stash apply //内容恢复到工作区(不删除)

28 .gitignore 文件

通常可以根据项目所用的语言,以github上的gitignore库为参照。

更新 .gitignore 文件后,将之前添加到库中的文件删除:

git rm --cached fileName

29 git 备份

哑协议 智能协议

git clone --bare file_path/.git nameYa.git //无进度条
git clone --bare file:///file_path//.git nameZhineng.git

推送

git remote add nameZhineng file:///file_path/nameZhineng.git 
git remote -v
git branch -av

本地协议 https协议 ssh协议

裸仓库,并不包含工作区,因此不能在这个目录下执行我们一般使用的 Git 命令。一般情况下是作为远端的中心仓库而存在的,即从裸仓库 clone 下来的本地仓库可以进行正常的 push 操作, 但是从一般仓库 clone 下来的本地仓库却不能 push。

git init --bare repoName

git和github的同步

账号注册,公私钥配置等略。

本地库同步到远端

配置github公私钥等,github有详细的教程。
需求:现在本地创建了git仓库,后续要同步到远端服务器。

git remote -v

git remote add name URL

git push name --all //相同分支下,如果本地和远端不同,该分支会推不上,需要 fetch 再 merge (等同于 pull )
git fetch name theSpecificBranch
git merge name/theSpecificBranch --allow-unrelated-histories 
git push name theSpecificBranch
//注意:上述操作会使当前 theSpecificBranch 的 commit 有 2 个父 commit;

关于 fast forward, 时刻关注 commit 树。

有一个案例,甲乙方合作的项目,甲方有安全限制导致乙方无法接入 git 服务器。此时,可以有如下解决方案:为对外合作项目单独搭建了一个 git 服务器,甲方员工用内网域名,乙方用外网域名,并且为外网IP设置了白名单,只有授权的IP才能访问公司的服务器。

34 - 38 多人单分支集成写作

多人修改不同文件

//准备工作
//配置本地环境
git config --add --local user.name "localName"
git config --local -l

//查看本地和远程分支信息
git branch -av

//建议本地和远程分支名字一致
git checkout -b local_banch_name remote_branch_name

//甲先做一些修改并 push 
//已然后也做了一些修改,并 commit
git fetch name 
git merge branch_name
git push name

注意: 当远程库有多个分支时,clone 库后并不会把所有的分支都同步到本地。比如远端有2个分支, clone 后本地只有一个:

$git branch -av 
  master                    
  remotes/origin/HEAD       
  remotes/origin/dev     
  remotes/origin/master

此时,还需要执行: git checkout -b dev origin/dev

同一文件被不同人修改

不同区域的修改,git 会“智能”地合并; 相同区域的修改,git 不会“智能”地合并,merge 后会失败,这时打开文件会可以看到 HEAD 和 local 的不同之处; 手动编辑后再继续 手动 merge。

再 push 之前,首先 fetch & merge / pull 下。

同时变更了文件名和文件内容

一个人修改了A的文件名,推送到服务器; 另一个人修改了A的内容,此时 pull 后 git 会智能地合并。

一个人修改了A的文件名,推送到服务器; 另一个人也修改了A的文件名,此时 pull 后 git 不会智能地合并。此时需要手动处理后再进行 merge 。

文件的管理最终是使用 blob,通过 hash 值可以判断文件内容的异同。 但同时修改了文件名后,显然这种需要修改者协商后才能进一步 merge。

39-40 集成使用禁忌

大原则:不要删除历史提交。即使是对提交的历史修改有不满意之处,也需要通过提交新 commit 的方式去修改。

禁止向集成分支执行 push -f 操作

force 情况下,这在团队协作的情况下是不允许的,因为可能会造成历史的丢失。

禁止向集成分支执行变更历史

因为每个写作者都有相同的历史变更,如果某人贸然地变更历史,会影响其他人的修改--有时需要逐个对 commit 逐个进行修改 merge。

如果历史丢失了,可以使用 git reflog 命令查找历史,然后利用 git reset --hard HAED@{n} 的方式恢复。