使用这12个Git的诀窍与技巧来令你的版本控制经验更加有用。java
Git,一个分布式版本控制系统,它已经成为了开源世界的源码控制默认工具,在4月7号12岁了。可是使用Git中更另人沮丧的是,你须要了解多少才能让你更有效的使用它。同时这也是使用Git中比较美妙的一件事,由于没有什么比发现一个新的小技巧来简化或提升你的工做流的效率更加使人快乐了。git
为了记念Git的12岁生日,这篇文章提供12个诀窍与技巧来让你的Git经验更加有用和强大,从一些你可能会忽视的基础开始到一些真正的强大技巧!面试
1. 你的 ~/.gitconfig 文件算法
在第一次用git命令来提交一个仓库的修改,你可能会首先看到像下面这种内容:shell
Please tell me who you are. Run git config --global user.email "you@example.com" git config --global user.name "Your Name" to set your account's default identity.
你可能尚未意识到那些命令正在修改~/.gitconfig文件的内容,这个文件就是Git存储全局配置选项的文件。经过你的~/.gitconfig文件你可要作不少事情,包括定义别名,永久的打开(或关闭)一些特定的命令选项,还能够修改Git如何工做的方面(例如:git diff使用哪一个diff算法,或者默认使用什么类型的的合并策略)。你甚至能够按条件地基于路径包含其余配置文件到一个仓库!使用“man git-config”查看全部细节。npm
2. 你的仓库的.gitconfig文件后端
在以前的技巧中,你可能会想知道在git config 命令中的—global标识是作什么的。它告诉Git更新“global”配置,也就是~/.gitconfig发现的这个配置。固然,拥有一个全局的配置表明了一个本地配置,并且足够确定的是,若是你省略—global选项,git config 会更新这个仓库本身的配置,这个配置文件存储在.git/config。多线程
在.git/config中设置的选项会推翻在~/.gitconfig文件中的对应设置。所以,例如,若是你须要在一个特定的仓库中使用一个不一样的邮箱地址,你能够运行“git config user.email "also_you@example.com"”。而后,你在这个仓库中提交会使用你单独配置的这个邮箱地址。若是你使用一个工做的电脑在开源项目中工做,可是但愿在这个项目中使用我的的邮箱地址,而其余在主Git配置中仍然使用工做邮箱,这一点是很是有用的。架构
在~/.gitconfig中能够设置的任何东西,均可以在.git/config中设置来对这个仓库作特定设置。在下面的这些技巧中,当我提到在你的~/.gitconfig文件中添加什么东西,同时也说明能够在特定的仓库的.git/config中添加来设置那个选项。分布式
三、别名
别名是你能够在你的~/.gitconfig文件里作的另一件事。他的工做原理就像shell命令行里的别名——设置一个新的命令名称来调用一个或者多个其余的命令,这些命令一般包括一些特定的选项或标识。别名对于你常用的那些又长又复杂的命令行是很是有效的。
你可使用git config命令来定义别名——例如,执行”git config —global —add alias.st status”命令后,会使得执行git st与执行git status作的是一样的事情——然而,我发现当定义别名的时候,只须要直接在~/.gitconfig文件里编辑一般会更加容易。
若是你选择这么作,你会发现~/.gitconfig文件就是一个INI文件,INI是一种带有特定段落的基础键值对文件格式。添加一个别名时,你将改变[alias]段落。例如:上面提到的定义相同的git st别名,须要添加下面这段代码:
[alias] st = status
(若是已经有了[alias]这个段落,只须要在这个段落中添加到第二行)
4. shell命令中的别名
别名不只仅是运行其余Git子命令——你也能够定义别名,这些别名能够运行其余shell命令。这是一个很好的方法来处理一个重复的、罕见的、复杂的任务:一旦你已经想到第一次怎么作,那就使用一个别名保存这个命令。例如,我有几个仓库是我fork了一个开源项目,并且在本地作了一些修改,这些修改不用贡献给这个项目。在项目的持续的开发的过程当中我想保持最新的版本,同时保留个人本地修改。为了完成这个想法,我须要按期地从upstream仓库中合并这些修改到个人fork——我定义一个别名“upstream-merge”来完成这个操做。定义以下:
upstream-merge = !"git fetch origin -v && git fetch upstream -v && git merge upstream/master && git push"
别名定义开始的这个“!”是告诉Git来经过shell运行这个命令。这个例子包括了运行一些git命令,可是使用这种方式定义别名能够运行任何shell命令。
(注意:若是你想复制个人upstream-merge别名,你将须要确认你有一个Git remote命名为upstream来指定这个你fork的upstream仓库。你能够经过“git remote add upstream ”来添加一个。)
5. 可视化提交图
若是你从事的是一个有不少分支活动的项目,有时可能很难掌握全部正在发生的工做以及它们之间的相关性。各类GUI工具可以让你弄清楚不一样分支的概况以及在所谓的“提交图”中提交记录。例如,如下是我使用 GitLab 提交图查看器进行可视化的一个存储卡的部分截图:
John Anderson, CC BY
若是你是专一于命令行的用户,就能够不在多个工具之间切换致使分心,这个工具在命令行上实现了相似图形界面的提交视图。经过 -- graph 参数获取 git 的记录:
John Anderson, CC BY
下面的命令能够获得同样的仓库可视化片断:
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
--graph 选项将图表添加到日志的左侧, --abbrev-commit 存储提交使用了 SHA 方法, --date=relative 表达式用相对的术语来表示日期,而且 --pretty 以 bit 格式处理自定义格式。我知道 git lg 的别名,它是我最常运行的10个命令之一。
6. 更优雅的强制推送(force-push)
有时,就跟你尽可能避免使用它同样困难的是,你会发现你须要运行 git push --force 来覆写你仓库的远程副本上的历史记录。你可能已获得了一些反馈,他们会要求你进行交互式的变基(rebase),或者你可能已经搞砸了,而且但愿隐藏证据。
当他人在仓库的远程副本的同一分支上进行改动后,会发生强制推送的风险。当你强制推送已重写的历史记录时,某些提交将会丢失。这是 git push --force-with-lease 出现的缘由 - 若是远程分支已更新,它不会容许你执行强制推送,这将确保你不会丢弃他人的工做。
7. git add -N
你是否使用过git commit -a在一次行动中提交你全部未完成的修改,只有在你push完你的提交后才发现git commit -a忽略了新添加的文件?解决这个问题你能够用git add -N(“通知”)来告诉Git你想把新添加的文件包含在提交中在你第一次实际提交以前。
8. git add -p
一最佳的实践为当使用Git时确保每一个提交只包含一个逻辑更改--无论是修复一个bug仍是(实现)一个新功能。然而, 有时当你工做 ,会在你的仓库中出现一个以上的修改 提交 。你怎么样把事情分开,使每一个提交只包含适当的修改呢?git add --patch来解救!
这个标志将会使git add命令查看你工做副本中全部的变动,询问你是否愿意将它提交,跳过,或者推迟决定(还有其余一些更强大的选项,你能够经过在运行这命令后选择?来查看)。git add -p是一个神奇的工具来生产结构良好的提交。
9. git checkout -p
与 git add -p相似,git checkout命令将使用 --patch 或 -p 选项,这会使 git 在本地工做副本中展现每一个“大块”的改动,并容许丢弃对应改动 —— 简单地说就是恢复本地工做副本到你改变以前的状态。
某些场景下这很是有用,例如,在你跟踪一个 bug 时引入了一堆调试日志语句,在修正了这个 bug 以后,你能够先使用 git checkout -p 删除全部新加的调试日志,以后使用 git add -p 来添加 bug 修复。没有比组合一个极好的、结构良好的提交更使人满意的了
10. Rebase with command execution
有些项目有一条规则,即存储库中的每一个提交都必须处于可工做状态 - 也就是说,在每次提交时,代码应该是可编译的,或运行测试套件应该不会失败的。当你在某分支上工做时间长时,但若是你最终由于某种缘由须要rebase时,那么跳过每一个变基后的提交以确保你没有意外引入一个中断是有些冗长乏味的。
幸运的是,git rebase已经支持了-x或--exec选项。git rebase -x 将在每次提交应用到rebase后运行该命令。所以,例如,若是你有一个项目,其中npm run tests会运行你的测试套件,那么在rebase期间应用每次提交后,git rebase -x npm run tests将会运行测试套件。这使你能够查看测试套件是否在任何变基后的提交中有失败状况,所以你能够确保测试套件在每次提交时仍能经过。
11. 基于时间修改的指南
不少Git子命令都接受一个修正的参数来决定命令做用于仓库的哪一个部分,多是某次特定的提交的 sha1 值,或者一个分支的名称,又或者是一个符号性的名称如 HEAD(表明当前检出分支最后一次的提交),除了这些简单的形式之外,你还能够附加一个指定的日期或时间做为参数,表示“这个时间的引用”。
这个功能在某些时候会变得十分有用,好比当你处理最新出现的 bug,自言自语道:“这个功能明明昨天仍是好好的,到底又改了些什么”,不用盯着满屏的 git 日志的输出试图弄清楚何时更改了提交,您只需运行 git diff HEAD@{yesterday},会看到从昨天以来的全部修改,这也适用于较长的时间段(例如 git diff HEAD@{'2 months ago'}) ,以及一个确切的日期(例如git diff HEAD@{'2010-01-01 12:00:00'})。
您还能够将这些基于日期的修改参数与使用修正参数的任何 Git 子命令一块儿使用。在 gitrevisions 手册页中有关于具体使用哪一种格式的详细信息。
12. 全知的 reflog
你是否是试过在 rebase 时干掉过某次提交,后来又发现你须要保留此次提交的一些东西?你可能以为这些提交的东西已经永远找不回来了,只能从头再来了。其实否则,但若是你在本地工做副本中提交了,提交就会进入到 "引用日志" ,你仍然能够访问到。
运行 git reflog 将在本地工做副本中显示当前分支的全部活动的列表,并为您提供每一个提交的 SHA1 值。一旦发现你 rebase 时放弃的那个提交,你能够运行 git checkout 来检出该次提交,复制好你须要的信息,而后再运行 git checkout HEAD 返回到分支最新的提交去。
但愿这些技巧中至少有一个能教你一些关于 Git 的新知识,Git 已经 12 岁了,在这个持续创新,不断添加新特性的项目里,你最喜欢哪一个技巧?
原文: https://opensource.com/articl...
译文: https://www.oschina.net/trans...
关注公众号Java技术栈回复"面试"获取我整理的2020最全面试题及答案。
推荐去个人博客阅读更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
以为不错,别忘了点赞+转发哦!