Git使用笔记

2014-07-18 Lingxian Kong 更多博文 » 博客 » GitHub »

原文链接 https://lingxiankong.github.io/2014-07-18-git-notes.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


配置

git config --list 查看系统变量的配置

export https_proxy="http://XXXXXX:XXXXXX@XXXXXX:8080/" 配置代理
密码中的特殊字符转义:

ampersand & (%26)
at @ (%40)
space (%20)
double-quote " (%22)
single-quote ' (%27)
colon : (%3A)

git config --global core.editor "vim" 修改默认编辑器,如果是仅修改当前repo的配置,删除global即可。

删除文件

1、手动删除
2、git rm [filename] (如果要删除之前修改过且已暂存的文件,要加-f)
3、提交

从暂存中移除,但不删除文件:git rm --cached readme.txt
取消暂存:git reset HEAD readme.txt
放弃未暂存文件所做的修改:git checkout -- readme.txt

文件重命名

git mv [file_from] [file_to],相当于:

$ mv README.txt README
$ git rm README.txt
$ git add README

忽略文件

在projec目录下:

$ cat .gitignore
*.[oa]
!lib.a
temp/

如果文件已经暂存,不会立即使用gitignore的新规则,此时先用git rm --cached filename

也可使用全局的.gitignore文件来对所有的代码库生效,比如新建文件~/.gitignore_global,然后执行:
git config --global core.excludesfile ~/.gitignore_global

全局忽略只能忽略那些原来没有被track的文件,如果已经纳入了版本管理,修改.gitignore也是无效的。
相关知识可以参见:https://segmentfault.com/q/1010000000430426

日志查看搜索

git log -p展开显示提交的内容差异;-2显示最近两条;--stat,仅显示简要的增改行数统计;
git log --pretty=oneline --no-merges 每个提交放在一行显示,不显示merge的记录
git log --graph --oneline --all
git log --graph --oneline --decorate 可以以图形化的方式显示branch关系
git log --since=2.weeks 查看两周内提交记录,或类似于--since="2008-10-01" --before="2008-11-01"
--author --committer
图形化工具:gitk

根据commit消息搜索:git log --grep="Something in the message"
搜索内容第一次出现或删除的提交:git log -S "TODO: Check for admin status"
按文件搜索:git log lib/foo.rb

标签

Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来签署或验证。

git show v1.2 查看tag信息
git tag v1.4.0 增加一个轻量tag

为先前的提交加tag:
1、git log --pretty=oneline
2、git tag -a v1.2 9fceb02 -m 'my version 1.4'(这是一个含附注tag,标签的签署不讲了,google吧)

推送tag到远端仓库:git push origin v1.2
一次性推送所有tag:git push origin --tags

远程仓库

git remote -v 查看远程仓库和克隆地址
git remote add [shortname] [url] 添加一个远程仓库
git remote show [remote-name] 显示远端仓库的详细信息
git remote rename [old_name] [new_name] 修改远端仓库在本地的简称
git remote rm [remote-name] 移除远端仓库
git fetch [repo] [branch] 抓取远程仓库的更新,但不合并(克隆操作会自动使用默认的 master 和 origin 名字)

git fetch origin branch1:branch2
使用远程branch1分支在本地创建branch2(但不会切换到该分支), 如果本地不存在branch2分支, 则会自动创建一个新的branch2分支, 如果本地存在branch2分支, 并且是`fast forward', 则自动合并两个分支, 否则, 会阻止以上操作

git pull [repo] [branch] 将远端分支自动合并到本地仓库中当前分支
git push [remote-name] [branch-name] 将本地仓库中的数据推送到远程仓库,一个示例(将本地分支提交到远程仓库的另一个分支):git push origin localbranch:remotebranch

分支

git checkout -b [分支名] [远程名]/[分支名] 创建分支(-d 删除分支,-D 强制删除)
删除远程服务器上的分支:git push origin :[remote_branch]
git merge --no-ff myfeature  --no-ff标记会使合并永远创建一个新的commit对象,在新的分支中保留myfeature分支的merge记录。

找到dev分支在master分支上的commitID:
git merge-base dev master 会显示dev和master两个分支的共同的commitID

Git References 介绍:https://git-scm.com/book/en/v2/Git-Internals-Git-References

  • .git/refs目录下 git 维护了一些 commit id 的映射,git update-ref可以修改映射关系,比如:git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
  • .git/HEAD总是指向当前 branch,其实它的内容是指向其他的 ref,可以使用命令设置:git symbolic-ref HEAD refs/heads/test

部分提交

比如为了fix 2个bug 修改同一个文件,但想分开提交。可以使用交互式 add
git add -p [file_name] 根据提示进行选择(这里选择s对要提交的内容进行分割):
输入 y 暂存块
输入 n 不暂存块
输入 e 手动编辑块
输入 d 退出或者跳转到下一个文件
输入 s 分割块

合并提交

比如想合并最后的两次提交,可以使用:
git rebase -i HEAD~2
与git add -p一样是交互式操作,它将询问你想要合并哪些提交。你pick(拣选)最近的提交然后squash(合并)旧的提交。

另一种场景是:如果你正并行工作在两个或者更多的分支上,你也许会发现一个存在于所有分支上的bug。如果你解决了一个分支上的这个bug,你可以拣选这个对应的提交应用到其他分支上,而不会弄乱其他文件或者提交。
在要应用bugfix的分支上执行:git cherry-pick [已解决bug分支的commit_hash]

储藏

https://git-scm.com/docs/git-stash

当你正在做一项复杂的工作时, 发现了一个和当前工作不相关但是又很讨厌的bug. 你这时想先修复bug再做手头的工作, 那么就可以用 git stash 来保存当前的工作状态, 等你修复完bug后, 再回到之前的工作里.

$ git stash save "work in progress for foo feature"
$ git stash list
$ git stash apply stash@{0}
$ git stash drop stash@{0}

补丁

git diff 查看尚未暂存的文件更新了哪些部分
git diff --cached 查看已经暂存起来的文件和上次提交之间的差异

git format-patch生成的补丁,是git专用的,也是日常工作中最常接触到的补丁类型,为每个提交生成一个 .patch 后缀的 mbox 文件,包含了提交的附加信息:比如作者,时间等。在此基础上使用git am命令即可将此补丁应用到当前分支。注意应用完之后,你会发现当前分支多了一次提交记录,并且有完整的信息,而不是简单的修改文件。

git format-patch master 获取所有dev分支在master分支基础上的patch文件
git format-patch HEAD^ 有几个^就会打几个patch,从最近一次打起
或者是git format-patch -1以及git format-patch -2

应用补丁:
1、对于git diff命令生成的补丁文件,使用git apply,是事务性操作,比patch命令严谨很多 ,可以先用git apply --check查看补丁是否能够干净顺利地应用到当前分支;
2、对于format-patch生成的补丁,使用git am,自动创建提交对象,如果出现冲突:

$ (fix the file)  
$ git add file  
$ git am --resolved  

回退

有几个概念:
working directory: 工作区,文件被修改后,add前就在这个区域;
index:文件被add之后在这个区域;

未提交

撤销所有修改,使工作目录回到上次提交后的状态:
git reset --hard HEAD
这个命令会把你工作目录中所有未提交的内容清空(但不包括 untracked files,比如新增的文件,要使用git clean). 从另一种角度来说, 这会让"git diff" 和"git diff --cached"命令的显示都变为空.
如果是回退一个文件:git checkout -- hello.py

如果想使工作目录跟 upstream 上 master 保持一致:git reset --hard origin/master

git reset用法
git reset [--hard|soft|mixed|merge|keep] [commit或HEAD] 根据--soft --mixed --hard,会对working directory、index、HEAD进行重置。
A). --hard:除了“Untracked files”,其他变更都被重置。即:重设index和working directory,自从commit以来在working directory和index中的任何改变都被丢弃,并把HEAD指向commit。
B). --soft:这个模式的效果是,执行完毕后,自从commit以来的所有改变都会显示在git status的"Changes to be committed"中,当然,还有“Untracked files”。即:恢复commit以来的index和working directory内容。即:not commited
C). --mixed:这个模式是默认模式,一般情况下够用。这个模式的效果是,自从commit以来的修改都会被保留,但会被标记成"Changes not staged for commit"。即:仅重置index,文件修改被转移到working directory中。即:not added

如何使用 reset 之前的 commit message 呢:

$ git commit ... 
$ git reset --soft HEAD^      (1) 
$ edit                        (2) 
$ git commit -a -c ORIG_HEAD  (3) 

(1) 当提交了之后,你又发现代码没有提交完整,或者你想重新编辑一下提交的comment,执行git reset --soft HEAD^,让working tree还跟reset之前一样,不作任何改变。HEAD^指向HEAD之前最近的一次commit。
(2) 对working tree下的文件做修改
(3) 然后使用reset之前那次commit的注释、作者、日期等信息重新提交。注意,当执行git reset命令时,git会把老的HEAD拷贝到文件.git/ORIG_HEAD中,在命令中可以使用ORIG_HEAD引用这个commit。commit 命令中 -a 参数的意思是告诉git,自动把所有修改的和删除的文件都放进stage area,未被git跟踪的新建的文件不受影响。commit命令中-c commit 或者 -C commit意思是拿已经提交的commit对象中的信息(作者,提交者,注释,时间戳等)提交,那么这条commit命令的意思就非常清晰了,把所有更改的文件加入stage area,并使用上次的提交信息重新提交。

已提交

1、创建新的commit修复错误
撤消(revert),其实对于revert的操作我用的很少,也不太明白revert的使用场景,等后续用得多了,再来补充.
2、修改提交来修复错误
就是常用的git commit --amend了,但如果错误的使用了 amend(原本是想独立的commit) 该如何恢复?
git reset --soft @{1},同时可以用git commit --reuse-message @{1}git commit -C @{1}拿到刚刚的commit message。这里有详细的解释,@{1} 意思是 where currentbranch pointed one step ago

技巧

有时上传一些大文件(比如图片),会出现fatal: The remote end hung up unexpectedly的提示,这是由于git/https的缓冲设置导致,可以通过如下方式解决:
git config http.postBuffer 524288000

使用github时,在git push往往会对用户名和密码进行认证,每次的输入很烦躁,效率很低。如果已经上传了本机的ssh公钥到github,那么可以配置项目目录下的.git/config文件:
remote.origin.url=git@github.com:{username}/{projectname}.git
比如我这里就是:url = git@github.com:LingxianKong/lingxiankong.github.io.git