开发中关于Git那些事

如果你想精通Git,直接到 Git官网 把这本ProGit掌握已足以Pro Git
此文主要介绍一切开发中常用的git命令和一些配置技巧(诸如git别名配置,log打印技巧,版本回退以及分支管理等)。
后来我又写了篇主要介绍Git变基的文章《开发中关于Git那些事(Git Rebasing)》,有兴趣的可以看看。

1.简介


Git与SVN相比而言,Git的好处自然不用多说,Git完全分布式文件管理系统,加上其简单速度,可以高效管理类似 Linux 内核一样的超大规模项目。完全分布式的系统,让你可以在公交车上,火车上,家中,甚至在厕所都可以敲代码。何时何地你都可以敲代码,甚至不需要网络。好不好使,开不开心?换是SVN,SVN服务器挂了,全部人停止敲代码,停下来八卦去吧。

Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异。这类系统(CVS,Subversion,Perforce,Bazaar 等等)每次记录有哪些文件作了更新,以及都更新了哪些行的什么内容。如同下图所示:

开发中关于Git那些事_第1张图片

但是,Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件作一快照,然后保存一个指向这次快 照的索引。为提高性能,若文件没有变化,Git 不会再次保存,而只对上次保存的快照作一连接。工作方式类似下图:
开发中关于Git那些事_第2张图片

对比可以发现,Git高效也在情理之中。
现在再简单介绍一下Git管理下文件的三种状态。对于任何一个文件,只要在Git管理下,那么该文件只有三种状态:已修改(modified),已暂存(staged)和已提交 (committed)。
已修改(modified): 文件被修改,但是还没有提交保存(也就是没有使用git add,此时使用git status显示为红色)。
已暂存(staged): 已修改的文件放入下次要提交的清单中(使用了git add后的状态,此时使用git status显示为绿色)。
已提交(committed): 该文件已经被安全地保存在本地数据库中(使用了git commit后,此时使用git status已经不存在该文件的任何信息)。
具体可以参考下面两幅图来理解。
开发中关于Git那些事_第3张图片

开发中关于Git那些事_第4张图片

2.配置用户信息


user和email,--global参数全局配置,当然你也可以不加此参数,不同的项目用不同的用户名和邮箱。

git config --global user.name Super
git config --global user.email 1342449****@163.com

3.配置全局别名


此配置在开发中相当重要,尤其是对于使用Terminal,习惯使用命令行的朋友,由于git不支持tab自动补全,每次想要看下工作目录 状态都要git status,相当耗时。除非你能确定你敲两个字母比六个字母用时少。

git config --global alias.st "status -s"
git config --global alias.ci "commit -m"
git config --global alias.aci "commit -a -m" #跳过使用暂缓区,直接将git add和git commit合并为一条命令
git config --global alias.lg "log --color --pretty=format:'%Cred%h - %Cgreen%an %C(yellow)| %ad | %Creset%s' --graph" //自定义log

第一条:git status是开发中使用最多最频繁的,至于-s 是简洁输入(Give the output in the short-format)
第二条:此条也使用频繁,但是我在开发中直接使用第三条跳过。
第三条:配置git aci 因为这样直接跳过使用暂存区域,对于已经跟踪的文件,我不要再此次使用git add加入暂缓区,然后再git commit提交到本地数据库,为了方便省事,直接将两条命令合并为一条,使用git aci "提交说明" 即可。省不省事,用下自然知道。
第四条:这里是我自定义的log信息,当然,一会看完本文你也可以自己格式化成自己喜欢的log格式。可以先看下效果,下图所示:


开发中关于Git那些事_第5张图片
自定义log

以后直接使用"git lg"即可,非常方便,显示简洁明了。

4.分支管理


git checkout -b dev origin/dev  // 拉取远程开发分支到本地并且切换到开发分支
git push dev origin/dev //
git branch new         // 创建新分支
git push origin new    // 将new分支推送到远程(git push [remote-name] [branch-name])
git push origin :new   // 删除远程分支,注意冒号位置
git branch -r -d origin/dev // 删除远程分支(同上一行命令,作用一样)
git brach -d new       // 删除本地分支,如果有没有merge的信息,确保该分支的确不用merge,直接使用-D强行删除
git merge dev          // 将dev分支合并到当前分支
git checkout master    // 切换到主分支
其他不再一一列出

关于实际开发中,独立开发的话其实两个分支完全够用,一个主分支(master),一个开发分支(develop)。多人的话就按功能模块和人员来具体新建分支即可。由于这边由我一人负责整个项目,那么分支的话,我就建立了一个develop分支,发布版本时切换到master处理即可。平时都在develop分支开发,如果此时发现线上版本有bug,那么只需要切换到master分支,修改bug,然后封版即可。处理好后切换到develop分支开发就可以了。当然最好还是把刚才在master修改bug的代码merge到当前的develop分支上。

还有一点使用技巧,也就是git stash的灵活使用。当我们正在当前分支编代码,突然某人中断你的思路,提出某功能需修改且比较紧急,更烦人的是当前的代码已经开始编写,而且改动了好多文件,重要的是不想中途进行git commit提交,此时git stash就发挥作用了。

git stash # 暂时隐藏,之后就可以正常切换分支了,当前的修改内容只是保存并且隐藏起来
git stash pop // 回复到之前的工作状态,默认pop的是最近的一条,这样就可以愉快的继续编写当时被中断的代码了

git stash可以执行多次,我们可以使用git stash list命令来查看清单。当然还有好多命令,可以使用git stash --help来查看。

开发中关于Git那些事_第6张图片

其实关于 git stash还有一个使用技巧,那就是如果当前修改了众多文件,突然又不想改了,想恢复到原来的样子。那么可能你会使用 git checkout命令来取消所有的更改,但是有种情况并不好使,因为你除了修改文件,还添加了一些文件或则拖入了一些文件到工程目录下,此时使用 git checkout然后再使用 git status查看的时候,会发现工作区多出了尚未识别的文件(处于等待add的状态)。在这个时候,使用 git stash是再好不过了,因为这样将所有git控制下的文件,包括之前的目录,全部还原到之前的状态(也就是说 git stash把新增的文件也暂时隐藏起来)。如果想彻底删掉,那就再把所有stash的列表清空吧,直接 git stash list看下,然后执行 git stash clear

还有一点,关于在Git服务器上删除分支,本地使用git branch -a依旧可以看到被删除的分支。好比你的代码托管到了开源中国(OSChina),你通过网站,在线删除分支,就会出现这种问题,稍微有点强迫症的自然受不了。此时可以使用 git fetch -p使fetch之后删除没有与远程分支对应的本地分支。 当然也可以通过查看远程分支。使用命令git remote show origin显示如下:

YJTSuper:yjtim super$ git remote show origin 
* remote origin
  Fetch URL: [email protected]:lingsui/yjtim.git
  Push  URL: [email protected]:lingsui/yjtim.git
  HEAD branch: master
  Remote branches:
    dev                      tracked
    im                       tracked
    master                   tracked
    proV2.3.0                tracked
    refs/remotes/origin/test stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    master merges with remote master
    show   merges with remote master
  Local refs configured for 'git push':
    dev       pushes to dev       (up to date)
    im        pushes to im        (fast-forwardable)
    master    pushes to master    (up to date)
    proV2.3.0 pushes to proV2.3.0 (up to date)

我们可以看到分支origin/test 已经过期(stale),可以使用命令git remote prune origin同样可以处理。

5.远程地址切换


如果想要切换远程地址,千万不要重新再初始化一个git代码仓库,使用git add重新添加。这样的好处只有一点,所有历史提交信息全部清空,不再保留,git clone时文件变小,理所当然,历史记录全部清空了麽。如果确定不保留,也建议这样做,关键时,谁写的代码更改了哪些东西很重要呀,还是选择保留吧。使用下面的方法,一行代码搞定,并且保留了所有的commit记录。

git remote -v  # 查看远程地址
git remote set-url origin https://git.oschina.net/HaiShengHuo/xxx.git # 更换远程地址, 新建一个项目不添加任何文件  在本地直接push即可

6.查看某次提交修改的具体文件和内容


方法一

git reflog 或则 git log --oneline
首先要列出最近的提交记录。

开发中关于Git那些事_第7张图片

git log 56c8822c --name-status
找到对应版本号,执行后可以看到本次提交之前的所有修改文件。

开发中关于Git那些事_第8张图片

git diff HEAD@{3} HEAD@{4}
具体某次修改的内容(具体某次提交的内容和上次提交的内容进行比较)。
git diff 56fd41f2 56c8822c
当然也可以这样,使用版本号,效果一样。

开发中关于Git那些事_第9张图片

这样假如之前修改过具体某些内容,以后还需要修改的话,找起来真的很方便。比如说某些bug好久之后才发现,又要回头去修改,而修改总要找到对应的代码进行修改吧。那么通过这样几行命令就定位到具体文件和位置了,方便且节省时间。找代码有技巧,但是"找"终究还是很浪费时间。这也告诉我们,commit 提交命令很重要,需要认真写,不可为了省事而乱写。

方法二

直接使用git log 4e732dee -p 或则 git log -p 4e732dee
其中4e732dee为版本哈希值

开发中关于Git那些事_第10张图片

方法三

git log --stat 4e732dee或者git log 4e732dee --stat
查看简洁文件变化

开发中关于Git那些事_第11张图片
简洁文件变化

查看本地修改的内容,尚未进行commit
直接使用git diff --stat

7.忽略跟踪


git checkout .   清空所有更改
以下命令是我们在项目中已经添加了.gitignore  但是中途突然不想再跟踪某文件
此时发现简单的在.gitignore文件中添加要忽略的文件是不起效的,因为该文件已
经被track,我们还需要将其状态改为 未track(其实只需删除暂缓区文件然后将操作体检即可)
git rm --cached Podfile.lock  将Podfile.lock从暂缓区删除,不再跟踪

8.备份


备份的话好一些,每次新的版本打一次tag,查看起来还是挺方便。不过不用也行。我不爱使用这个。

git tag -a WeChat1.0 -m "version 1.0" :给版本打上标签
git tag : 查看所有的标签
git push origin WeChat1.0 : 将WeChat1.0 push 到默认分支

9.版本回退


git reset --hard HEAD # 没有提交的情况下进行版本回退
git reset --hard HEAD # 没有提交的情况下进行版本回退
git reset --hard HEAD^ # 回退到上一个版本
git reset --hard HEAD^^ # 回退到指定回退到某个版本
git reset --hard 版本号(至少前5位) # 回退到前几个版本
git reset --hard~1
git revert c011eb3c20ba6fb38cc94fe5a8dda366a3990c61 # 注意该行命令 reset和revert有本质区别

注意:开发中一般托管代码到远程代码仓库,比如Github或则OSChina,加入本地已经使用git push到远程代码仓库,在本地使用git reset回退再push明显是不可行的。因为git reset直接回退到历史中的某个Hash值,但是使用git revert就不一样了。git revert将作为一次新提交(新的Hash值)来撤销某次更改而不是历史中的某个Hash值,此时再push到远程代码仓库情理之中。当然你嫌麻烦也可以使用git reset 后再使用 git push -f强制 push 到远程代码仓库。
reset和revert区别:
• git reset 3c7bdf2 回到3c7bdf2,3c7bdf2之前的commit都会保留,3c7bdf2之后的修改都会被退回到暂存区。
• git revert 3c7bdf2 生成一个新的commit来撤销3c7bdf2,此次提交之前的commit都会被保留。
可以参考博客git revert和git reset的区别

10.日志


想回顾下提交历史,可以使用 git log 命令,其中有个--pretty 参数可以配置

git log --pretty=oneline
git log --pretty=format:"%h - %an, %ar : %s"
git log --pretty=format:"%h %s" --graph
git log --since=2.weeks

自己可以试一下,这里附上参数说明,自己可以随意配置,当然log字体颜色也都是可以修改的,不再细述。

%H  # 提交对象(commit)的完整哈希字串 %h 提交对象的简短哈希字串
%T  # 树对象(tree)的完整哈希字串
%t  # 树对象的简短哈希字串
%P  # 父对象(parent)的完整哈希字串 %p 父对象的简短哈希字串
%an # 作者(author)的名字
%ae # 作者的电子邮件地址
%ad # 作者修订日期(可以用 -date= 选项定制格式) %ar 作者修订日期,按多久以前的方式显示
%cn # 提交者(committer)的名字
%ce # 提交者的电子邮件地址
%cd # 提交日期
%cr # 提交日期,按多久以前的方式显示 %s 提交说明

时间和提交者过滤

-(n)                  # 仅显示最近的 n 条提交。
--since, --after    # 仅显示指定时间之后的提交。
--until, --before   # 仅显示指定时间之前的提交。
--author            # 仅显示指定作者相关的提交。
--committer         # 仅显示指定提交者相关提交。

你一定奇怪作者(author)提交者(committer)之间究竟有何差别,其实作者指的是实际作出修改 的人,提交者指的是最后将此工作成果提交到仓库的人。所以,当你为某个项目发去补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。我们会在第五章再详细介绍两者之间的细致差别。

11.忽略某些文件


文件 .gitignore 的格式规范如下:
• 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
• 可以使用标准的 glob 模式匹配。
• 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。星号(*)匹配零个或多个任意字符;[abc] 匹配 任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?) 只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配 (比如 [0-9] 表示匹配所有 0 到 9 的数字)。

# 此为注释 – 将被 Git 忽略
*.[oa]  Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现 的,我们用不着跟踪它们的版本
*~  Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件 (比如 Emacs)都用这样的文件名保存副本
*.a # 忽略所有 .a 结尾的文件
!lib.a # 但 lib.a 除外
/TODO # 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO build/ # 忽略 build/ 目录下的所有文件
doc/*.txt # 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt

你可能感兴趣的:(开发中关于Git那些事)