git教程 git笔记 git常用 git使用 git操作 git简明 git版本控制 git仓库

git 使用

初次运行 Git 前的配置

查看、修改 gitconfig

git config --list --show-origin

git config --global user.name "John Doe"
git config --global user.email [email protected]

记录每次更新到仓库

查看当前文件状态

git status
git status -s					# 状态简览

跟踪新文件或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等

git add README

查看未暂存或未提交差异

git diff 																		# 未暂存差异
git diff --cached (git diff --staged)   	 # 未提交差异

提交

git commit -m "add README.m"

移除文件

git rm README.m

从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中,比如忘记添加 .gitignore 文件

git rm --cached README
git rm --cached log/\*.log			# 支持正则, 注意* 之前的反斜杠 \,因为 Git 有它自己的文件模式扩展匹配方式

移动文件

git mv file_from file_to 
## 相当于
mv file_from file_to
git rm fire_from
git add file_to

查看提交历史

最近两次提交差异

git log -p -2

每次提交的简略的统计信息

git log --stat

不同于默认格式的方式展示提交历史,查看方式oneline, shortfullfuller 可以用

git log --pretty=oneline

定制显示记录格式 常用选项,(作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人)

git log --pretty=format:"%h - %an, %ar : %s"

onelineformat 与另一个 log 选项 --graph 结合使用时尤其有用,形象地展示你的分支、合并历史

git log --pretty=format:"%h %s" --graph

git log 的 常用选项

限制输出长度,限制输出的选项

git log --since=2.weeks								# 最近两周的所有提交
git log -S function_name							# 找出添加或删除了对某一个特定函数的引用的提交
git log 1.txt 2.txt 									# 某些文件或者目录的历史提交
git log -S function_name -- 1.txt     # 两个短划线隔开之前的选项和后面限定的路径名
git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" \
   --before="2008-11-01" --no-merges -- t/           # 查看 Junio Hamano 在 2008 年 10 月其间, 除了合并提交之外的哪一个提交修改了测试文件

撤消操作

重新提交

git commit --amend

取消暂存的文件

git restore --staged README.m
git reset HEAD README.m (老版本)

撤消对文件的修改,危险命令,你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它

git restore README.m
git checkout -- README.m (老版本)

远程仓库的使用

查看远程仓库

git remote
git remote -v  					# 显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL

添加远程仓库,

git remote add  
git remote add origin https://github.com/paulboone/ticgit

从远程仓库中抓取与拉取

git fetch    		 #必须注意 git fetch 命令只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作
git pull 				 #如果你的当前分支设置了跟踪远程分支,自动抓取后合并该远程分支到当前分支

推送到远程仓库

git push  
git push origin master			# 克隆时通常会自动帮你设置好那两个名字

查看某个远程仓库

git remote show 

远程仓库的重命名与移除

git remote rename pb paul			# 重命名
git remote remove paul				# 移除

打标签

列出标签

git tag
git tag -l "v1.8.5*"			# 标签过滤

创建标签

轻量标签很像一个不会改变的分支——它只是某个特定提交的引用

而附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。

git tag -a v1.4 -m "my version 1.4"				# 附注标签
git show v1.4															# 查看标签信息和与之对应的提交信息
git tag v1.4-lw														# 轻量标签
git tag -a v1.2 9fceb02										# 在某个提交上打标签

共享标签

git push origin v1.5
git push origin --tags					# 一次性推送很多标签

删除标签

git tag -d v1.4-lw													# 不会从任何远程仓库中移除这个标签
git push  :refs/tags/ 			# 来更新你的远程仓库
git push origin :refs/tags/v1.4-lw					# 方式一
git push origin --delete 					# 方式二

检出标签,查看某个标签所指向的文件版本

git checkout 2.0.0								# 会使你的仓库处于“分离头指针(detached HEAD)”的状态
git checkout -b version2 v2.0.0		# 如果你需要进行更改,比如你要修复旧版本中的错误,那么通常需要创建一个新分支

Git 别名

git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'			# 取消暂存文件
git config --global alias.last 'log -1 HEAD'					# 最后一次提交
git config --global alias.visual '!gitk'							# 执行外部命令,而不是一个Git子命令,命令前面加入!符号

分支新建与合并

分支创建

git branch testing
git log --oneline --decorate  	# 查看各个分支当前所指的对象

分支切换

git checkout testing
git chekkout -b testing      	# 创建一个新分支后立即切换过去,相当于 git branch,git checkout

查看分叉历史

git log --oneline --decorate --graph --all

删除分支

git branch -d hotfix

合并分支

git checkout master			# 检出到你想合并入的分支
git merge iss53					# 合并 iss53 分支到 master 分支

遇到冲突时的分支合并

<<<<<<< HEAD:index.html
<div id="footer">contact : [email protected]div>
=======
<div id="footer">
 please contact us at [email protected]
div>
>>>>>>> iss53:index.html

这表示 HEAD 所指示的版本(也就是你的 master 分支所在的位置,因为你在运行 merge 命令的时候已经检出到了这个分支)在这个区段的上半部分(======= 的上半部分),而 iss53 分支所指示的版本在 ======= 的下半部分。

git mergetool						# 启动一个合适的可视化合并工具

分支管理

查看分支

git branch			 				# 分支的一个列表
git branch -v    				# 查看每一个分支的最后一次提交
git branch --merged 		# 哪些分支已经合并到当前分支, 这个列表中分支名字前没有*号的分支通常可以使用 git branch -d 删除掉
git branch --no-merged	# 尚未合并到当前分支
git branch --no-merged master  # 不必检出到 master, 查看未合并到 master 分支的有哪些

分支开发工作流

远程分支

查看远程分支

git ls-remote    		# 获得远程引用的完整列表
git remote show     # 获得远程分支的更多信息

远程跟踪分支是远程分支状态的引用, 请将它们看做书签,它们以 / 的形式命名,例如 origin/master分支

同步数据

git fetch 				# 从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master 指针到更新之后的位置
git fetch origin

推送

git push  
git push origin serverfix			# Git 自动将 serverfix 分支名字展开为 refs/heads/serverfix:refs/heads/serverfix
git push origin serverfix:serverfix  		# 也可以运行, 推送本地的 serverfix 分支,将其作为远程仓库的 serverfix 分支
git push origin serverfix:awesomebranch # 本地的 serverfix 分支推送到远程仓库上的 awesomebranch 分支

可以运行 git merge origin/serverfix 将这些工作合并到当前所在的分支。 如果想要在自己的 serverfix 分支上工作,可以将其建立在远程跟踪分支之上

git checkout -b serverfix origin/serverfix

跟踪分支

git checkout -b  /
git checkout --track origin/serverfix				# Git 提供了 --track 快捷方式
git checkout serverfix   # 如果你尝试检出的分支 (a) 不存在且 (b) 刚好只有一个名字与之匹配的远程分支,那么 Git 就会为你创建一个跟踪分支
git checkout -b sf origin/serverfix 	# 如果想要将本地分支与远程分支设置为不同的名字
git branch -u origin/serverfix     # 设置已有的本地分支跟踪一个刚刚拉取下来的远程分支,或者想要修改正在跟踪的上游分支, 你可以在任意时间使用 -u 或 --set-upstream-to 选项运行 git branch 来显式地设置
# git merge @{u} 来取代 git merge origin/master

查看设置的所有跟踪分支

git branch -vv
git fetch --all; git branch -vv  	# 统计最新的领先与落后数字,需要在运行此命令前抓取所有的远程仓库

拉取

git fetch # 从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容
git pull 	#  在大多数情况下它的含义是一个 git fetch 紧接着一个 git merge 命令

删除远程分支

git push origin --delete serverfix 	# 只是从服务器上移除这个指针, Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。

变基

提取在 C4 中引入的补丁和修改,然后在 C3 的基础上应用一次,变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。

git checkout experiment		# 检出 experiment 分支, 将它变基到 master 分支上
git rebase master
git checkout master				# 回到 master 分支,进行一次快进合并
git merge experiment

在对两个分支进行变基时,所生成的“重放”并不一定要在目标分支上应用,你也可以指定另外的一个分支进行应用

将 client 中的修改合并到主分支并发布,但暂时并不想合并 server 中的修改

git rebase --onto master server client 	#  取出 client 分支,找出它从 server 分支分歧之后的补丁, 然后把这些补丁在 master 分支上重放一遍,让 client 看起来像直接基于 master 修改一样

直接将主题分支 (即本例中的 server)变基到目标分支(即 master)上。 这样做能省去你先切换到 server 分支,再对其执行变基命令的多个步骤

git rebase  
git rebase master server

变基的风险

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基

变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。

解决方法用变基解决变基

另一种简单的方法是使用 git pull --rebase 命令而不是直接 git pull。 又或者你可以自己手动完成这个过程,先 git fetch,再 git rebase teamone/master

如果你习惯使用 git pull ,同时又希望默认使用选项 --rebase,你可以执行这条语句 git config --global pull.rebase true 来更改 pull.rebase 的默认配置

只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。

向一个项目贡献

git diff --check			 # 找到可能的空白错误并将它们为你列出来
git add --patch 			 # 部分暂存文件
git format-patch -M origin/master 	# 创建补丁, -M 开关告诉 Git 查找重命名

维护项目

git apply --check 0001-seeing-if-this-helps-the-gem.patch   # 检查补丁是否可以顺利应用
git apply /tmp/patch-ruby-client.patch											#	应用一个使用 git diff 生成补丁
## 建议使用 git format-patch 打补丁
git am 0001-limit-log-function.patch												# 应用一个由 format-patch 命令生成的补丁
git am --resolved 																					# 解决冲突后继续应用下一个补丁
git am -3 0001-seeing-if-this-helps-the-gem.patch						#  -3 选项来使 Git 尝试进行三方合并
git am -3 -i mbox																						# 交互模式下运行 am 命令
git log contrib --not master																# 查看每次提交所引入的具体修改
git diff master...contrib               										# 该分支与 master 分支的共同祖先进行比较
git cherry-pick e43a6																				# 将提交 e43a6 拉取到 master 分支

准备一次发布

git archive master --prefix='project/' | gzip > `git describe master`.tar.gz		# 最新的快照归档
git archive master --prefix='project/' --format=zip > `git describe master`.zip # 创建一个 zip 压缩包

提交简报

git shortlog --no-merges master --not v1.0.1 	#自 v1.0.1 以来的所有提交

选择修订版本

简短的 SHA-1

git log --abbrev-commit --pretty=oneline

分支引用

git show topic1							# 假设 topic1 分支指向提交 ca82a6d...
git rev-parse topic1				# 某个分支指向哪个特定的 SHA-1

引用日志, 引用日志只存在于本地仓库

git reflog
git show HEAD@{5}							# HEAD 在五次前的所指向的提交
git show master@{yesterday} 	# master 分支在昨天的时候指向了哪个提交
git log -g master 						# git log 输出格式的引用日志信息

祖先引用

git show HEAD^								# 该引用的上一个提交
git show HEAD^^								# HEAD的父提交的父提交
git show HEAD^2							  #	HEAD的第二父提交, 这个语法只适用于合并的提交,因为合并提交会有多个父提交
# 另一种指明祖先提交的方法是 ~   
git show HEAD~2 							# 代表“第一父提交的第一父提交”
# 组合使用
git show HEAD~3^2							# 来取得之前引用的第二父提交(假设它是一个合并提交)

提交区间

## 双点
git log master..experiment			# 在 experiment 分支中而不在 master 分支中的提交
git log origin/master..HEAD			# 查看你即将推送到远端的内容

# 下列三个命令是等价
git log refA..refB
git log ^refA refB
git log refB --not refA

## 多点
git log refA refB ^refC					# 被 refA 或 refB 包含的但是不被 refC 包含的提交
git log refA refB --not refC

## 三点
git log master...experiment     # master 或者 experiment 中包含的但不是两者共有的提交
git log --left-right master...experiment  # 它会显示每个提交到底处于哪一侧的分支

交互式暂存

git add -i 								# --interactive 

暂存补丁

git add -p 								# --patch, 通常情况下可以输入 y 或 n 来选择是否要暂存每一个区

更进一步地,可以使用 git reset --patch 命令的补丁模式来部分重置文件, 通过 git checkout --patch 命令来部分检出文件与 git stash save --patch 命令来部分暂存文件

贮藏与清理

贮藏工作

git stash 或 git stash push	 # 贮藏
git stash list                # 查看贮藏的东西
git stash apply								# 刚刚贮藏的工作重新应用
git stash apply stash@{2}			# 应用其中一个更旧的贮藏
git stash apply --index				# 尝试重新应用暂存的修改
git stash drop								# 移除的贮藏
git stash pop									# 应用贮藏然后立即从栈上扔掉它

贮藏的创意性使用

git stash --keep-index			# 不贮藏已暂存的内容
git stash -u 								# --include-untracked, 藏任何未跟踪文件
git stash --patch						# 交互式地提示哪些改动想要贮藏

从贮藏创建一个分支

git stash branch testchanges

清理工作目录

git stash --all 			# 更安全的移除每一样东西并存放在栈中
git clean							# 去除冗余文件或者清理工作目录
git clean -f -d				# 移除工作目录中所有未追踪的文件以及空的子目录
git clean -d -n				# 做一次演习然后告诉你 将要 移除什么

搜索

Git Grep 不仅仅可以可以搜索工作目录,还可以搜索任意的 Git 树

git grep -n gmtime_r						# -n 或 --line-number 选项数来输出 Git 找到的匹配行的行号
git grep --count gmtime_r				# -c 或 --count 仅包括那些包含匹配字符串的文件,以及每个文件中包含了多少个匹配
git grep -p gmtime_r *.c				#  -p 或 --show-function 选项来显示每一个匹配的字符串所在的方法或函数
git grep --break --heading \
    -n -e '#define' --and \( -e LINK -e BUF_MAX \) v1.8.0
# 查看在旧版本 1.8.0 的 Git 代码库中定义了常量名包含 “LINK” 或者 “BUF_MAX” 这两个字符串的行 (这里也用到了 --break 和 --heading 选项来使输出更加容易阅读)

Git 日志搜索

git log -S ZLIB_BUF_MAX --oneline		# 找到 ZLIB_BUF_MAX 常量是什么时候引入的
																		# 你可以使用 -G 选项来使用正则表达式搜索

行日志搜索

git log -L :git_deflate_bound:zlib.c				# 展示代码中一行或者一个函数的历史
git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c	# 提供一个正则表达式

重写历史

修改最后一次提交,修正会改变提交的 SHA-1 校验和。 它类似于一个小的变基

git commit --amend
git commit --amend --no-edit			# 避免不必要的编辑器环节

修改多个提交信息

git rebase -i HEAD~3							# 从上到下的依次重演每一个提交引入的修改,每一个修改了提交信息的提交及其 所有后裔都会被重写

重新排序提交,压缩提交,拆分提交

git rebase -i HEAD~3      # 后修改顺序
# squash 压缩提交
# edit 然后 git reset HEAD^, 几个提交后,运行 git rebase --continue

核武器级选项:filter-branch

想要通过脚本的方式改写大量提交的话可以使用它——例如,全局修改你的邮箱地址或从每一个提交中移除一个文件,git filter-branch 有很多陷阱,不再推荐使用它来重写历史。 请考虑使用 git-filter-repo,它是一个 Python 脚本,相比大多数使用 filter-branch 的应用来说,它做得要更好。它的文档和源码可访问 https://github.com/newren/git-filter-repo 获取。

git filter-branch --tree-filter 'rm -f passwords.txt' HEAD 	# 从整个提交历史中移除一个叫做 passwords.txt 的文件, 为了让 filter-branch 在所有分支上运行,可以给命令传递 --all 选项

使一个子目录做为新的根目录

git filter-branch --subdirectory-filter trunk HEAD  # 让 trunk 子目录作为每一个提交的新的项目根目录

全局修改邮箱地址

git filter-branch --commit-filter '
        if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
        then
                GIT_AUTHOR_NAME="Scott Chacon";
                GIT_AUTHOR_EMAIL="[email protected]";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

重置揭密

git cat-file -p HEAD				# 底层命令
git ls-tree -r HEAD
git ls-files -s						

重置的作用

git reset --soft HEAD~		# 把该分支移动回原来的位置,而不会改变索引和工作目录
git reset --mixed HEAD~   # 默认,它依然会撤销一上次 提交,但还会 取消暂存 所有的东西
git reset --hard HEAD~    # 让工作目录看起来像索引

通过路径来重置

git reset file.txt 	# 其实是 git reset --mixed HEAD file.txt 的简写, 本质上只是将 file.txt 从 HEAD 复制到索引中,还有 取消暂存文件 的实际效果
git reset eb43bf file.txt		# 指定一个提交来拉取该文件的对应版本, 又可以运行 git add 添加它,也可以接受一个 --patch 选项来一块一块地取消暂存的内容。 这样你就可以根据选择来取消暂存或恢复内容了

压缩

git reset --soft HEAD~2
git commit 

检出

不带路径

运行 git checkout [branch] 与运行 git reset --hard [branch] 非常相似,它会更新所有三棵树使其看起来像 [branch],不过有两点重要的区别

  1. checkout 对工作目录是安全的

  2. reset 会移动 HEAD 分支的指向,而 checkout 只会移动 HEAD 自身来指向另一个分支。

带路径

运行 checkout 的另一种方式就是指定一个文件路径,这会像 reset 一样不会移动 HEAD。 它就像 git reset [branch] file 那样用该次提交中的那个文件来更新索引,但是它也会覆盖工作目录中对应的文件。它就像是 git reset --hard [branch] file(如果 reset 允许你这样运行的话), 这样对工作目录并不安全,它也不会移动 HEAD

高级合并

合并冲突

git merge --abort 				# 简单地退出合并
git reset --hard HEAD			# 回到上一次提交的状态

忽略空白

git merge -Xignore-space-change whitespace  # 这次使用 -Xignore-all-space 或 -Xignore-space-change 选项。 第一个选项在比较行时 完全忽略 空白修改,第二个选项将一个空白符与多个连续的空白字符视作等价的

手动文件再合并

git show :1:hello.rb > hello.common.rb				# Stage 1 是它们共同的祖先版本
git show :2:hello.rb > hello.ours.rb					# stage 2 是你的版本
git show :3:hello.rb > hello.theirs.rb				# stage 3 你将要合并入的版本(“theirs”)
git ls-files -u 		# 使用 ls-files -u 底层命令来得到这些文件的 Git blob 对象的实际 SHA-1 值

# 手动修改 hello.theirs.rb 文件
git merge-file -p \
    hello.ours.rb hello.common.rb hello.theirs.rb > hello.rb 	# 命令来重新合并
git diff --ours													# 看看合并引入了什么
git diff --theirs	-b										# 合并的结果与他们那边有什么不同, -b 来去除空白
git diff --base													# 查看文件在两边是如何改动的
git clean -f														# 清理我们为手动合并而创建但不再有用的额外文件

检出冲

git checkout --conflict=diff3 hello.rb		# 重新检出文件并替换合并冲突标记
git checkout --ours 和 --theirs 					 # 选择留下一边, 当有二进制文件冲突时这可能会特别有用

合并日志

 git log --oneline --left-right HEAD...MERGE_HEAD		# 得到此次合并中包含的每一个分支的所有独立提交的列表
 git log --oneline --left-right --merge			# 显示任何一边接触了合并冲突文件的提交
 git log --oneline --left-right -p 					# 得到所有冲突文件的区别

组合式差异格式

git diff
git log --cc -p -1				# 查看冲突是如何解决的

撤消合并

# 方法1: 修复引用
git reset --hard HEAD~   # 方法的缺点是它会重写历史,应当避免使用 reset
# 方法2: 还原提交
git revert -m 1 HEAD     # -m 1 标记指出 “mainline” 需要被保留下来的父结点
git revert ^M						 # 如果重新 git merge topic 了

其他类型的合并

git merge -Xours mundo				# 使用 ours 快速合并
git merge-file --ours 				# 来合并单个文件
git merge -s ours mundo       # 本质上会做一次假的合并
git diff HEAD HEAD~

子树合并

Rerere

重用记录的解决方案

git config --global rerere.enabled true			# 你也可以通过在特定的仓库中创建 .git/rr-cache 目录来开启它
git rerere status   # 通过 git rerere status 告诉你它记录的合并前状态
git rerere diff     # 显示解决方案的当前状态——开始解决前与解决后的样子
git ls-files -u			# 查看冲突文件的之前、左边与右边版本
# 修改解决,然后 commit
git reset --hard HEAD^		# 来回滚分支,然后 checkout 另外一个分支
git rebase master					# 得到了相同的合并冲突, 我们看这个文件,会发现它已经被解决了
git checkout --conflict=merge hello.rb 	# 重新恢复到冲突时候的文件状态

使用 Git 调试

文件标注

git blame -L 69,82 Makefile			# 第 69 行到第 82 行每一行分别来自哪个提交和提交者
git blame -C -L 141,153 GITPackUpload.m # 看到代码块的原始出处

二分查找

git bisect start				# 来启动
git bisect bad					# 告诉系统当前你所在的提交是有问题的
git bisect good v1.0		# 告诉 bisect 已知的最后一次正常状态是哪次提交
git bisect good 				# 来告诉 Git测试结果是没有问题的, 然后继续寻找
git bisect bad					# 发现这个提交下是有问题的
git bisect reset				# 最后,重置你的 HEAD 指针到最开始的位置
git bisect start HEAD v1.0					# 参数来设定这两个提交,第一个参数是项目不正常的提交,第二个参数是项目正常的提交
git bisect run test-error.sh				# Git 会自动在每个被检出的提交里执行 test-error.sh, 脚本在项目是正常的情况下返回 0,在不正常的情况下返回非 0

子模块

开始使用子模块

git submodule add https://github.com/chaconinc/DbConnector # 后面加上想要跟踪的项目的相对或绝对 URL 来添加新的子模块
git diff --cached --submodule			# 查看另一个是项目文件夹记录

克隆含有子模块的项目

git submodule init				# 用来初始化本地配置文件
git submodule update			# 从该项目中抓取所有数据并检出父项目中列出的合适的提交
git clone --recurse-submodules https:// # 自动初始化并更新仓库中的每一个子模块
git submodule update --init --recursive # 还要初始化、抓取并检出任何嵌套的子模块

在包含子模块的项目上工作

git fetch							# 进入到子目录中
git merge 
git diff --submodule	# 进入主目录
git config --global diff.submodule log  	# 不想每次输入 --submodle
git submodule update --remote DbConnector # 不想在子目录中手动抓取与合并

未完…

打包

git bundle create repo.bundle HEAD master			# 打包
git clone repo.bundle repo										# 接收者使用
git bundle create commits.bundle master ^9a466c5	# 打包区间
git bundle verify ../commits.bundle							# 检查这个文件是否是一个合法的 Git 包
git bundle list-heads ../commits.bundle       #  查看这边包里可以导入哪些分支
git fetch ../commits.bundle master:other-master # 可以使用 fetch 或者 pull 命令从包中导入提交

替换

凭证存储

配置 Git

 git config --global commit.template ~/.gitmessage.txt		# 模版

格式化与多余的空白字符

默认被打开的三个选项是:

blank-at-eol,查找行尾的空格;

blank-at-eof,盯住文件底部的空行;

space-before-tab,警惕行头 tab 前面的空格。

默认被关闭的三个选项是:

indent-with-non-tab,揪出以空格而非 tab 开头的行(你可以用 tabwidth 选项控制它);

tab-in-indent,监视在行头表示缩进的 tab;

cr-at-eol,告诉 Git 忽略行尾的回车。

git config --global core.autocrlf true   # 提交时自动地把回车和换行转换成换行,而在检出代码时把换行转换成回车和换行
git config --global core.autocrlf input 	# 提交时把回车和换行转换成换行,检出时不转换

git config --global core.whitespace \
    trailing-space,-space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol # 不指定它或在它前面加个 -
    
git apply --whitespace=warn   # 探测到这些问题
git apply --whitespace=fix    # 自动修正此问题

服务器端配置

Git 属性

Git 钩子

底层命令与上层命令

Git 是一个内容寻址(content-addressable)文件系统。

config							# 包含项目特有的配置选项
description					# 仅供 GitWeb 程序使用,我们无需关心
HEAD								# 指向目前被检出的分支																	(**重要**)
hooks/							# 包含客户端或服务端的钩子脚本(hook scripts
info/								# 包含一个全局性排除(global exclude)文件
objects/						# 存储所有数据内容  																		(**重要**)
refs/								# 目录存储指向数据(分支、远程仓库和标签等)的提交对象的指针		(**重要**)
										#(尚待创建的)index 文件保存暂存区信息											(**重要**)

Git 对象

echo 'test content' | git hash-object -w --stdin			# 创建一个新的数据对象并将它手动存入你的新 Git 数据库中
git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 # 取回数据

# 对一个文件进行简单的版本控制
echo 'version 1' > test.txt		
git hash-object -w test.txt
echo 'version 2' > test.txt		# 写入新内容
git hash-object -w test.txt
git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt # 从对象数据库中取回它的第一个版本
# 记住文件的每一个版本所对应的 SHA-1 值并不现实, 文件名并没有被保存——我们仅保存了文件的内容
git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a # 告诉我们其内部存储的任何对象类型

树对象

git cat-file -p master^{tree}   # master 分支上最新的提交所指向的树对象
git update-index --add --cacheinfo 100644 \
  83baae61804e65cc73a7201a7252750c76066a30 test.txt   # 通过暂存一些文件来创建一个暂存区
git write-tree				# 将暂存区内容写入一个树对象
git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579 # 把树对象读入暂存区, 可以通过对该命令指定 --prefix 选项,将一个已有的树对象作为子树读入暂存区

提交对象

echo 'first commit' | git commit-tree d8329f			# 创建一个提交对象, 它先指定一个顶层树对象,代表当前项目快照
git log --stat 1a410e

这就是每次我们运行 git addgit commit 命令时,Git 所做的工作实质就是将被改写的文件保存为数据对象, 更新暂存区,记录树对象,最后创建一个指明了顶层树对象和父提交的提交对象。

对象存储

Git 是如何存储其对象的

Git 引用

这基本就是 Git 分支的本质:一个指向某一系列提交之首的指针或引用

echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master # 创建一个新引用来帮助记忆最新提交所在的位置, 从技术上讲我们只需简单地做如下操作
git log --pretty=oneline master
git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9 # 更安全
git update-ref refs/heads/test cac0ca  # 第二个提交上创建一个分支

HEAD 引用

git symbolic-ref HEAD	 refs/heads/test		# 可以手动编辑该文件, 可以借助此命令来查看 HEAD 引用对应的值

标签引用

git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d # 像这样创建一个轻量标签
git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag' # 若要创建一个附注标签,Git 会创建一个标签对象,并记录一个引用来指向该标签对象,而不是直接指向提交对象

远程引用

远程引用和分支(位于 refs/heads 目录下的引用)之间最主要的区别在于,远程引用是只读的

包文件

Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。 要看到打包过程,你可以手动执行 git gc 命令让 Git 对对象进行打包

git gc

Git 是如何做到这点的? Git 打包对象时,会查找命名及大小相近的文件,并只保存文件不同版本之间的差异内容。 你可以查看包文件,观察它是如何节省空间的。 git verify-pack 这个底层命令可以让你查看已打包的内容:

git verify-pack -v .git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.idx

引用规范

传输协议

维护与数据恢复

git reset --hard 1a410efbd13591db07 # 硬重置丢失数据
git reflog			# 引用日志
git branch recover-branch ab1afef	# 创建一个新的分支指向这个提交来恢复它
rm -Rf .git/logs/ #  如果已经没有引用日志了
git fsck --full		# 检查数据库的完整性, 显示出所有没有被其他对象指向的对象

移除对象

git rm git.tgz				# 移除大文件
git count-objects -v  # 快速的查看占用空间大小, size-pack 的数值指的是你的包文件以 KB 为单位计算的大小
git verify-pack -v .git/objects/pack/pack-29…69.idx  | sort -k 3 -n | tail -3 # 如果你执行 git gc 命令,所有的对象将被放入一个包文件中,你可以通过运行 git verify-pack 命令, 然后对输出内容的第三列(即文件大小)进行排序,从而找出这个大文件。
git rev-list --objects --all | grep 82c99a3 	# 找出具体是哪个文件
git log --oneline --branches -- git.tgz       # 查看哪些提交对这个文件产生改动
git filter-branch --index-filter 'git rm --ignore-unmatch --cached git.tgz' -- 7b30847^.. # 重写 7b30847 提交之后的所有提交来从 Git 历史中完全移除这个文件
rm -Rf .git/refs/original			# 通过 filter-branch 选项添加的新引用中还存有对这个文件的引用
rm -Rf .git/logs/							# 删除引用日志
git gc												# 重新打包
git count-objects -v # 可以从 size 的值看出,这个大文件还在你的松散对象中,并没有消失;但是它不会在推送或接下来的克隆中出现,这才是最重要的
git prune --expire now  # 完全地移除那个对象

环境变量

来自:git官网

你可能感兴趣的:(工具使用,git,版本控制,代码管理,git仓库,svn)