引言
整理了下之前极客时间上《玩转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}
的方式恢复。
Comments