Git使用笔记

2014-07-18

本博客所有文章采用的授权方式为 自由转载-非商用-非衍生-保持署名 ,转载请务必注明出处,谢谢。

声明:
本博客欢迎转发,但请保留原作者信息!
新浪微博:@Lingxian_kong;
博客地址:孔令贤的博客;
内容系本人学习、研究和总结,如有雷同,实属荣幸!

配置

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 每个提交放在一行显示
git log –graph –oneline –all
git log –graph –oneline –decorate 可以以图形化的方式显示branch关系
git log –no-merges 不显示merge的记录
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 tag -l 列出tags
git show v1.2 查看tag信息
git tag v1.4-lw 增加一个轻量tag
切换到tag所在的commit:git checkout 1.0alpha

为先前的提交加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 设定当前分支的 FETCH_HEAD’ 为远程服务器的branch1分支, 这个操作是git pull origin branch1的第一步

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

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

交互式add

推荐阅读交互式git add -p: https://git-scm.com/book/zh/v1/Git-%E5%B7%A5%E5%85%B7-%E4%BA%A4%E4%BA%92%E5%BC%8F%E6%9A%82%E5%AD%98
如果你编辑了一个文件,只想提交其中一部分而不包括其他未完成编辑的部分,或者把文档、空白字符从大量的修改中分开提交,可以使用交互式add。

Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
y - stage this hunk
n - do not stage this hunk
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

分支

git checkout -b [分支名] [远程名]/[分支名] 创建分支(-d 删除分支,-D 强制删除)
git checkout [branch_name] 切换到分支(-b 新建并切换) git branch -m [oldname] [newname] 修改分支名称,修改当前分支名称:git branch -m [newname]
删除远程服务器上的分支:git push origin :[remote_branch]
git merge [new_branch] 将新分支的内容合并到当前分支,如果遇到冲突,可以使用git status查看冲突的文件,手工解决后,git add,比如:

<<<<<<< HEAD:index.html  
<div id="footer">contact : email.support@github.com</div>  
=======  
<div id="footer">  
  please contact us at support@github.com  
</div>  
>>>>>>> iss53:index.html  

git merge –no-ff myfeature –no-ff标记会使合并永远创建一个新的commit对象,在新的分支中保留myfeature分支的merge记录。

或者使用rebase(衍合):

git checkout dev
git rebase master

生成dev分支的patch,在master分支打一遍,使dev成为master分支的直接下游(会修改dev的提交历史),这样,在maste分支执行git merge dev就完成了分支的合并;
git rebase –onto master server client 取出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍(暂不合并server分支),然后在进入master分支进行merge操作。
git rebase master server 随后衍合server分支
使用衍合需要注意:旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。如果把衍合当成一种在推送之前清理提交历史的手段,而且仅仅衍合那些尚未公开的提交对象,就没问题。
git rebase -i 进入rebase的交互模式,参考这里

git branch –merged,查看哪些分支已合并到当前分支
git branch –no-merged,查看那些分支尚未合并到当前分支,此时也可以强制删除分支:git branch -D [branch_name]

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

部分提交

比如为了fix2个bug修改同一个文件,但想分开提交。可以使用:
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 format-patch命令生成的patch文件,包含了提交的附加信息:比如作者,时间等。在此基础上使用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 diff” 和”git diff –cached”命令的显示都变为空.
如果是回退一个文件:git checkout – hello.py

对于untracked files,使用git clean命令。 https://git-scm.com/docs/git-clean

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

git reset HEAD file…会将git index中file内容删除,重新放回working directory中,即未被add的状态。

一个示例:假如你想要丢弃你所有的本地改动与提交,可以到服务器上获取最新的版本并将你本地主分支指向到它。

git fetch origin
git reset --hard origin/master

另一个示例:

$ 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。这里有详细的解释。

技巧

有时上传一些大文件(比如图片),会出现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


参考文档: http://gitbook.liuhui998.com/index.html

文章评论

comments powered by Disqus


章节列表