常用git命令

November 27, 2013 | 8 Minute Read

所有的命令不理解都可以git help 来查看manaul的帮助,最好的参考来的

最简单最常用的

git clone http://192.168.1.100:8080/git/repos/freediameter.git
git pull                #从远程仓库下载更新到本地
git branch  -r          #查看远程分支名字
git checkout -b <branch> <remote>/<branch>       # 把远程分支代码checkout到本地新分支
$ git checkout -b work/issue/92 origin/work/issue/92
$ git branch
  master
* work/issue/92

提交所有改动了的文件

git status 看看哪些文件被修改了

git commit -p  这个自动让你选择所有修改过的文件,然后提交。 当然用GUI程序集成的功能,commit的时候自动就选了所有改动过的文件,更方便了。用命令行,必须的用-p参数啊,自己用git help commit查看
类似的有:

git add  -p
git log -p
git checkout -p

利用回收站保存临时修改

git stash save  保存当前已经修改的但还没有提交的文件的状态。
然后去做其他的修改,checkout 到另外branch 等等
git stash pop  还原到原来的那些文件状态。
非常方便的,还有一些其他命令可以git help stash 看帮助

利用回收站功能丢弃当前的所有修改

git stash
git stash clear

删除远程分支

git push origin --delete <branchName>

git log 输出里面 commit右边sha-1  hash值标识一个commit改动,但一般使用前面几个就个标识一个commit了,看文档一般用前面4位。应该这个sha-1前4位出现冲突的情况都比较少才能这样用吧
git checkout -b fixes 1b6d

修改分支名字

如果新的分支名字已经存在要用-M ,不然-m
git branch -m  work/issue93  work/issue/93

查看本地分支与远程分支关联关系

git branch -vv

rebase调整分支的继承结构

以前 work/issue/92是从master 继承而来的。
做了下面这个命令之后,work/issue/92分支会变成从 origin/freediameter-1.1继承而来。
当前branch所有的修改也合并过去。
git rebase origin/freediameter-1.1
git push -f   参数覆盖远程分支上面已经存在的work/issue/92 分支

丢弃所有未commit和已经commit的修改

$ git reset  --hard HEAD
做完这个所有被修改的文件,没有提交的都被丢弃。还原回最初的状态。
git help reset,自己reset的帮助,可以用来撤销前面几次的commit记录,merge 记录,add 记录等。文档举例很有参考价值。

HEAD好似一个游标,通常指向最新提交,随最新提交向前移动。一些Git命令让你来移动 它。 例如:

$ git reset HEAD~3
将立即向回移动HEAD三个提交。这样所有Git命令都表现得好似你没有做那最后三个提交, 然而你的文件保持在现在的状态。具体应用参见帮助页。

但如何回到将来呢?过去的提交对将来一无所知。

如果你有原先Head的SHA1值,那么:

$ git reset 1b6d
但假设你从来没有记下呢?别担心,像这些命令,Git保存原先的Head为一个叫 ORGI_HEAD的标记,你可以安全体面的返回:

$ git reset ORIG_HEAD

这个还原上次提交,但过程会被记录下来被作为一个新的提交
 git revert 1b6d
讲撤销给定哈希值的提交。本撤销被记录为一个新的提交

git checkout -f   force选项可以强制checkout,并且丢弃本地位未提交的修改

git checkout -- <pathspec>  丢弃某个文件未提交的修改 


重做多个commit的记录,把多个commit合并到一个里面里面
先用reset回撤到commit e20bec14,但保留文件修改, 然后再重写提交记录,把多个commit的记录换成一个等

git reset --soft e20bec14
git commit -m "重写的commit修改状态"

清除目录下所有不在git版本仓库里面的文件,类似make clean的效果

git clean
git clean -x

查看修改历史

git log --oneline --decorate --graph

查看某次commit修改了那些内容
git show <commit hash>
比如
git show a0a394bc5fd6

git reflog
查看分支历史,比git log 看起来方便一些。

按commit 消息内容查找
git log -g --grep="查找关键字"

按时间查找
git log --after="2019-01-20 00:00" --before="2019-01-21 12:00"

显示指定文件的历史记录
git log -p filename

按文件内容变化查找
git log --all -S "文件内容关键字" filename

指定格式化,生成两个版本的changelog 等,可以插入html模板,markdown模板等
git log v3.1...v3.0 --pretty=format:'%H %s'

查看某个commit修改的文件名列表和行数统计

git diff --stat  # 带上 --stat 函数会统计 文件名列表和 每个文件修改了多少行

查看每个人贡献了多少个commit

git shortlog -sn

制作patch

git  diff可以查看当前没提交的修改,应该也是可以用来制作patch的在 Windows的 GUI里面,就很容易用图形界面的查看diff。不过git format-patch  好处是可以包含commit的历史记录

1.

把所有当前分支的修改,但修改不再origin分支里面的
Extract all commits which are in the current branch but not in the origin branch:
$ git format-patch origin

$ git format-patch  freediameter-1.2   从原始分支freediameter-1.2开始到当前的所有修改

在当前目录下会输出所有的patch,一个commit历史记录一个patch文件。默认用commit 信息里面的第一行来作为文件名

0001-add-PDN-Connection-ID-AVP.patch
0002-add-Dynamic-Address-Flag-AVP.patch
0003-add-IMSI-Unauthenticated-Flag-AVP.patch

一般工作都是从一个原始分支新建一个分支来工作,然后上面这个输出这个新分支的所有修改的命令比较合适吧。

2.

--stdout 把所有的输出到打印标准输出,不创建多个patch文件了。我比较喜欢这种方式
git format-patch --stdout freediameter-1.2

3. –

-<n>  指定一个数字,表示最近的几次commit修改

git format-patch --stdout -1    最近的1个commit
git format-patch --stdout -3    最近的3个commit

Extract three topmost commits from the current branch and format them as e-mailable patches:
$ git format-patch -3

4.

用 git am命令可以应用这个patch文件。 相当于patch -p<n>命令吧,不过专门针对git patch,可能历史记录更好吧。
Extract commits between revisions R1 and R2, and apply them on top of the current branch using git am to cherry-pick them:
$ git format-patch -k --stdout R1..R2 | git am -3 -k
可以参考 “gitrevisions” 的帮助文档查看revision的语法,一种是直接用git log 里面看到commit 后面的<sha1> 哈希数字(一般用前面几位数字就可以个完整标识一个commit),一种是常用HEAD等关键字。
比如上面的语法就来自下面这个range表示方法
<rev1>..<rev2>
Include commits that are reachable from <rev2> but exclude those that are reachable from <rev1>. When either <rev1> or <rev2> is omitted, it defaults to HEAD.

参考gitrevisions 帮助文档 Git/doc/git/html/gitrevisions.html 后面有个图示解释
<rev>^, e.g. HEAD^, v1.5.1^0
A suffix ^ to a revision parameter means the first parent of that commit object. ^<n> means the <n>th parent (i.e. <rev>^ is equivalent to <rev>^1). As a special rule, <rev>^0 means the commit itself and is used when <rev> is the object name of a tag object that refers to a commit object.
<rev>~<n>, e.g. master~3
A suffix ~<n> to a revision parameter means the commit object that is the <n>th generation ancestor of the named commit object, following only the first parents. I.e. <rev>~3 is equivalent to <rev>^^^ which is equivalent to <rev>^1^1^1. See below for an illustration of the usage of this form.
原文有个图示,解释的比较清楚,<rev>^加数字是多继承的第几个parent节点,<rev>~是前面的第几代parent
所下面这个命令在单继承树上等价于 git format-patch -2 命令
$ git format-patch HEAD~2


应用补丁
git apply --stat  001.patch
git apply --check 001.patch
git apply  001.patch
git am --signoff < fix_empty_poster.patch

修改最后一次提交的信息

$ git commit --amend
会启动一个编辑器窗口,让你重写上次commit信息,但要配置editor才行,参考最后面的editor配置。Windows的git可以用他内置的 vim。
刚提交,但你期望你输入的是一条不同的信息?那么键入:

$ git commit --amend
来改变上一条信息。意识到你还忘记了加一个文件?运行git add来加,然后运行上面的 命令。

希望在上次提交里包括多一点的改动?那么就做这些改动并运行:

$ git commit --amend -a

还有git rebase -i HEAD~10 这样还原大量的修改的,参考下面的两个文档

把提交状态回撤到commit e20bec14,但文件修改保留, 然后重写提交记录,把多个commit的记录换成一个等

git reset --soft e20bec14
git commit -m "重写commit修改状态"

重写多个提交记录之前的commit的信息,把修复问题fixup代码合并到多个提交记录之前的commit去(修复之前的commit的bug,又不想单独搞一次commit时),重排多个commi顺序,自由选择commit历史等

这个要使用下面这个命令

git rebase [-i | --interactive]  <commit_hash|branch>

会启动一个编辑器,让你交互式的自由选择和重写commit的列表,
把commit之前的pick改成reword就可以重新该commit的信息了。
参考 git help rebase的文档,这个一个非常强大的命令

git commit -a --fixup 34bda33
git rebase --interactive --autosquash master

--fixup 表示这次提交时对之前34bda33 那个commit的存在问题的修复。
--autosquash 就会自动把这两个关联问题的commit合并成一个commit

如果是重排commit顺序和丢掉一些commit,那个更简单了,修改那个 列表就可以了,
参考git help rebase的文档INTERACTIVE MODE的章节。


错误的git reset之后 怎么恢复

git fsck --lost-found  查看文件状态
git reflog show  查看HEAD的修改记录,找到被删commit的hash值,然后git reset恢复
git reset HEAD@{1} 最简单的还原HEAD到上次修改之前的状态

git的设置

比如user name都记录到commit 里面

git config user.name xxx
git config user.email xxx@xxx.com

其实就是修改配置文件,也可以直接去改动吧

$(prefix)/etc/gitconfig
~/.gitconfig
 $GIT_DIR/config   .git/config
分别对应参数 --system, --global, --local 。
默认就是--local在当前的代码仓库的 .git/config文件里面设置
自己git help config看一下
git config --list 可以查看当前设置

git的默认编辑器修改

git config --global core.editor "vim"
git是按照设置GIT_EDITOR 环境变量,core.editor 设置,VISUAL 环境变量, EDITOR 环境变量的顺序来选择到底使用那个编辑器来写commit信息的。

export GIT_EDITOR=vim
export VISUAL=vim
export EDITOR=vim

查看历史

git log -p -2   显示最近两次commit的内容差异diff

git log --stat  显示commit历史的修改行数

字符图形显示log的继承关系
git log --pretty=format:"%h %s" --graph

查看某个分支/tag是否包含某个提交commit在里面

git branch --contains  xxxxx
git tag --contains  xxxxx

远程服务器地址修改

git remote -v     查看远程仓库
git remote add pb git://github.com/paulboone/ticgit.git 添加远程仓库pb
git fetch pb  从远程仓库pb取内容
git remote rename pb paul 远程仓库的删除和重命名
git remote rm paul
git remote show origin  查看远程仓库内容

git remote -v
origin	http://192.168.100.105:8080/git/repos/myproject.git (fetch)
origin	http://192.168.100.105:8080/git/repos/myproject.git (push)
git remote set-url origin http://192.168.4.203:8080/git/repos/myproject.git

选择性的把某个分支上面的某次commit merge过来

git  cherry-pick  dfd484f12

格式化代码源文件

git stripspace
可以把代码行尾的空格删掉,还有空白行删掉,很好用的命令
git diff  --check 可以检查这种“空格错误”
--check
Warn if changes introduce whitespace errors. What are considered whitespace errors is controlled by core.whitespace configuration. By default, trailing whitespaces (including lines that solely consist of whitespaces) and a space character that is immediately followed by a tab character inside the initial indent of the line are considered whitespace errors. Exits with non-zero status if problems are found. Not compatible with --exit-code.

打包git目录树的所有文件

git archive --format=zip -o  webrtc_latest.zip HEAD
可以方便的把git的目录打包到一个压缩包里面,可以指定某个branch之类的。

使用内置的git server 来在windows 和linux 机器之间同步文件 ,使用多个remote仓库

在windows上面用git命令启动一个简单的git server , 为 D盘的  smsc 目录提供git 协议访问。
----------------------------
git daemon --verbose --base-path=/d  --export-all  --listen=192.168.56.1 D://smsc
     --base-path=/d : 告诉服务在再d 盘查找文件的根目录。 这样  git://192.168.56.1/smsc
                       最终 对应的就是  /d/smsc 目录
     --export-all : d盘 的所有git 仓库,解释目录下没有名字为“git-daemon-export-ok ”的文件
     --listen=192.168.56.1 : 绑定一个内部ip,只有自己主机和虚拟机可以访问
     最后一个参数,指定提供服务的目录只限制为 D://smsc, 不要把d盘的其他git仓库也
     放到服务器上,如果省略就是所有的git 仓库都导出了。不过mingw会自动对参数里面文件路径做很特殊的处理,导致路径的写法很奇怪。
     在windows 命令提示符下面的语法是
     C:\Git\bin\git.exe daemon --verbose --base-path=D: --export-all  --listen=192.168.56.1 D:/smsc

     启动的git server  默认的 tcp端口是 DEFAULT_GIT_PORT = 9418  可以用 --port  指定
     默认server是只读的,支持git pull fecth,要支持git push
     需要配置daemon.receivepack 为true,或者直接在命令行里面制定 --enable=receive-pack
     C:\Git\bin\git.exe daemon --verbose --enable=receive-pack --export-all --listen=192.168.56.1  --base-path=D:  D:/smsc
     
     注意git默认拒绝远程push修改本地当前分支,必须配置下面这个才能让远程push修改本地当前分支,不然就要先在本地checkout到切换到
     其他分支上面,再在远程机器执行git push到对应分支的操作
     git config --local receive.denyCurrentBranch ignore
     

linux 通过添加多个远程仓库来访问windows上面的 git daemon 服务器
-----------------------------------------------------
git clone git://192.168.56.1/smsc
直接在linux上面clone/pull不成功,会收到下面这样错误,windows端不知道为什么发了一个 tcp reset 
   fatal: read error: Connection reset by peer
   fatal: early EOF
   fatal: index-pack failed
但windows本地 clone windows本地dammon服务器是可以的,好像是msys git的一个bug, *网上有人说需要在git server运行后
的git bash 命令终端窗口用鼠标选中一些字符,再在linux那边git pull就可以绕过这个bug了*。试了一下确实可以。选中命令窗口的字符
之后windows应该是会把线程挂起吧,可能是多线程同步之类的bug,打印线程退出导致socket被不正确的释放了?
有时把本地clone出来的目录复制到linux,再git pull是可以。
或者像下面这样配置好remote 然后再pull应该也可以

git remote add windows git://192.168.56.1/smsc
git fetch windows
git pull windows
这样 windows下面是自己私有的机器的修改,origin下面是公用服务器的代码。 还能直接用git diff来比较
windows的私有修改和 origin下面各个分支的差别。

windows和linux换行相关的配置

# text源码文件出现混合的windows换行crlf和linux换行lf时报告错误
core.safecrlf = true

# text源码文件默认使用linux方式换行
core.eol=lf

# 不要git在checkout时自动把文件换行转成当前系统的换行
core.autocrlf=false


#指定特定后缀名的文件的换行
Here is an example that will make Git normalize .txt, .vcproj and .sh files, ensure that .vcproj files have CRLF and .sh files have LF in the working directory, and prevent .jpg files from being normalized regardless of their content.

*.txt		text
*.vcproj	eol=crlf
*.sh		eol=lf
*.jpg		-text

# 这个跟core.autocrlf=true类似,但会自动转换所有text文件的换行,需要配置上面这些文件扩展名和eol属性的设定。“core.autocrlf=true” 支持在checkout 时才做转换。 下面这个应该在checkin时也做转换。
If you want to interoperate with a source code management system that enforces end-of-line normalization, or you simply want all text files in your repository to be normalized, you should instead set the text attribute to "auto" for all files.

*	text=auto


参考git文档 https://git-scm.com/docs/gitattributes  ,可以使用下面的步骤来统一转换。

When text=auto normalization is enabled in an existing repository, any text files containing CRLFs should be normalized. If they are not they will be normalized the next time someone tries to change them, causing unfortunate misattribution. From a clean working directory:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force Git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"


If any files that should not be normalized show up in git status, unset their text attribute before running git add -u.
manual.pdf	-text

Conversely, text files that Git does not detect can have normalization enabled manually.
weirdchars.txt	text


git add itself does not touch the files in the work tree, the next checkout would, so the safety triggers;

git apply to update a text file with a patch does touch the files in the work tree, but the operation is about text files and CRLF conversion is about fixing the line ending inconsistencies, so the safety does not trigger;

git diff itself does not touch the files in the work tree, it is often run to inspect the changes you intend to next git add. To catch potential problems early, safety triggers.

Release 版本发布

git tag -d v1.0.1
git tag -a v1.0.1

git describe  会生成一个版本字符串,包含commit的哈希值等等
git log --format="%H" -n 1   会显示最后一次commit的id

查看另外一个分支的文件内容

git show main:README.md

学习参考:

Git Magic http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/zh_cn/index.html

图书 Git Pocket Guide.pdf

Pro Git bookhttp://git-scm.com/book/zh/