mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-22 23:00:57 +08:00
PUB:20150211 25 Tips for Intermediate Git Users
@zpl1025
This commit is contained in:
parent
06be2e6b47
commit
e28011b47e
@ -1,6 +1,6 @@
|
||||
25个给git熟手的技巧
|
||||
25个 Git 进阶技巧
|
||||
================================================================================
|
||||
我已经使用git差不多18个月了,觉得自己对它应该已经非常了解。然后来自GitHub的[Scott Chacon][1]过来给LVS做培训,[LVS是一个赌博软件供应商和开发商][2](从2013年开始的合同),而我在第一天里就学到了很多。
|
||||
我已经使用git差不多18个月了,觉得自己对它应该已经非常了解。然后来自GitHub的[Scott Chacon][1]过来给LVS做培训([LVS是一个赌博软件供应商和开发商][2],从2013年开始的合同),而我在第一天里就学到了很多。
|
||||
|
||||
作为一个对git感觉良好的人,我觉得分享从社区里掌握的一些有价值的信息,也许能帮某人解决问题而不用做太深入研究。
|
||||
|
||||
@ -15,21 +15,21 @@
|
||||
|
||||
#### 2. Git是基于指针的 ####
|
||||
|
||||
保存在git里的一切都是文件。当你创建一个提交的时候,会建立一个包含你的提交信息和相关数据(名字,邮件地址,日期/时间,前一个提交,等等)的文件,并把它链接到一个文件树中。文件树中包含了对象或其他树的列表。对象或容器是和本次提交相关的实际内容(也是一个文件,你想了解的话,尽管文件名并没有包含在对象里,而是在树中)。所有这些文件都使用对象的SHA-1哈希值作为文件名。
|
||||
保存在git里的一切都是文件。当你创建一个提交的时候,会建立一个包含你的提交信息和相关数据(名字,邮件地址,日期/时间,前一个提交,等等)的文件,并把它链接到一个树文件中。这个树文件中包含了对象或其他树的列表。这里的提到的对象(或二进制大对象)是和本次提交相关的实际内容(它也是一个文件,另外,尽管文件名并没有包含在对象里,但是存储在树中)。所有这些文件都使用对象的SHA-1哈希值作为文件名。
|
||||
|
||||
用这种方式,分支和标签就是简单的文件(基本上是这样),包含指向实际提交的SHA-1哈希值。使用这些索引会带来优秀的灵活性和速度,比如创建一个新分支就只要简单地创建一个包含分支名字和所分出的那个提交的SHA-1索引的文件。当然,你不需要自己做这些,而只要使用Git命令行工具(或者GUI),但是实际上就是这么简单。
|
||||
用这种方式,分支和标签就是简单的文件(基本上是这样),包含指向该提交的SHA-1哈希值。使用这些索引会带来优秀的灵活性和速度,比如创建一个新分支就是简单地用分支名字和所分出的那个提交的SHA-1索引来创建一个文件。当然,你不需要自己做这些,而只要使用Git命令行工具(或者GUI),但是实际上就是这么简单。
|
||||
|
||||
你也许听说过叫HEAD的索引。这只是简单的一个文件,包含了你当前指向的那个提交的SHA-1索引值。如果你正在解决一次合并冲突然后看到了HEAD,这并不是一个特别的分支或分值上一个必须的特殊点,只是标明你当前所在位置。
|
||||
你也许听说过叫HEAD的索引。这只是简单的一个文件,包含了你当前指向的那个提交的SHA-1索引值。如果你正在解决一次合并冲突然后看到了HEAD,这并不是一个特别的分支或分支上的一个必需的特殊位置,只是标明你当前所在位置。
|
||||
|
||||
所有的分支指针都保存在.git/refs/heads里,HEAD在.git/HEAD里,而标签保存在.git/refs/tags里 - 自己可以放心地进去看看。
|
||||
所有的分支指针都保存在.git/refs/heads里,HEAD在.git/HEAD里,而标签保存在.git/refs/tags里 - 自己可以随便进去看看。
|
||||
|
||||
#### 3. 两个父节点 - 当然! ####
|
||||
#### 3. 两个爸爸(父节点) - 你没看错! ####
|
||||
|
||||
在历史中查看一个合并提交的信息时,你将看到有两个父节点(相对于一般工作上的常规提交的情况)。第一个父节点是你所在的分支,第二个是你合并过来的分支。
|
||||
在历史中查看一个合并提交的信息时,你将看到有两个父节点(不同于工作副本上的常规提交的情况)。第一个父节点是你所在的分支,第二个是你合并过来的分支。
|
||||
|
||||
#### 4. 合并冲突 ####
|
||||
|
||||
目前我相信你碰到过合并冲突并且解决过。通常是编辑一下文件,去掉<<<<,====,>>>>标志,保留需要留下的代码。有时能够看到这两个修改之前的代码会很不错,比如,在这两个分支上有冲突的改动之前。下面是一种方式:
|
||||
目前我相信你碰到过合并冲突并且解决过。通常是编辑一下文件,去掉<<<<,====,>>>>标志,保留需要留下的代码。有时能够看到这两个修改之前的代码会很不错,比如,在这两个现在冲突的分支之前的改动。下面是一种方式:
|
||||
|
||||
$ git diff --merge
|
||||
diff --cc dummy.rb
|
||||
@ -45,14 +45,14 @@
|
||||
end
|
||||
end
|
||||
|
||||
如果是二进制文件,比较差异就没那么简单了...通常你要做的就是测试这个二进制文件的两个版本来决定保留哪个(或者在二进制文件编辑器里手工复制冲突部分)。从一个特定分支获取文件拷贝(比如说你在合并master和feature123):
|
||||
如果是二进制文件,比较差异就没那么简单了...通常你要做的就是测试这个二进制文件的两个版本来决定保留哪个(或者在二进制文件编辑器里手工复制冲突部分)。从一个特定分支获取文件拷贝(比如说你在合并master和feature123两个分支):
|
||||
|
||||
$ git checkout master flash/foo.fla # 或者...
|
||||
$ git checkout feature132 flash/foo.fla
|
||||
$ # 然后...
|
||||
$ git add flash/foo.fla
|
||||
|
||||
另一种方式是通过git输出文件 - 你可以输出到另外的文件名,然后再重命名正确的文件(当你决定了要用哪个)为正常的文件名:
|
||||
另一种方式是通过git输出文件 - 你可以输出到另外的文件名,然后当你决定了要用哪个后,再将选定的正确文件复制为正常的文件名:
|
||||
|
||||
$ git show master:flash/foo.fla > master-foo.fla
|
||||
$ git show feature132:flash/foo.fla > feature132-foo.fla
|
||||
@ -71,7 +71,7 @@
|
||||
|
||||
#### 5. 远端服务器 ####
|
||||
|
||||
git的一个超强大的功能就是可以有不止一个远端服务器(实际上你一直都在一个本地仓库上工作)。你并不是一定都要有写权限,你可以有多个可以读取的服务器(用来合并他们的工作)然后写入其他仓库。添加一个新的远端服务器很简单:
|
||||
git的一个超强大的功能就是可以有不止一个远端服务器(实际上你一直都在一个本地仓库上工作)。你并不是一定都要有这些服务器的写权限,你可以有多个可以读取的服务器(用来合并他们的工作)然后写入到另外一个仓库。添加一个新的远端服务器很简单:
|
||||
|
||||
$ git remote add john git@github.com:johnsomeone/someproject.git
|
||||
|
||||
@ -87,10 +87,10 @@ git的一个超强大的功能就是可以有不止一个远端服务器(实
|
||||
|
||||
$ git diff master..john/master
|
||||
|
||||
你也可以查看不在远端分支的HEAD的改动:
|
||||
你也可以查看没有在远端分支上的HEAD的改动:
|
||||
|
||||
$ git log remote/branch..
|
||||
# 注意:..后面没有结束的refspec
|
||||
# 注意:..后面没有结束的特定引用
|
||||
|
||||
#### 6. 标签 ####
|
||||
|
||||
@ -99,7 +99,7 @@ git的一个超强大的功能就是可以有不止一个远端服务器(实
|
||||
建立这两种类型的标签都很简单(只有一个命令行开关的差异)
|
||||
|
||||
$ git tag to-be-tested
|
||||
$ git tag -a v1.1.0 # 会提示输入标签信息
|
||||
$ git tag -a v1.1.0 # 会提示输入标签的信息
|
||||
|
||||
#### 7. 建立分支 ####
|
||||
|
||||
@ -108,7 +108,7 @@ git的一个超强大的功能就是可以有不止一个远端服务器(实
|
||||
$ git branch feature132
|
||||
$ git checkout feature132
|
||||
|
||||
当然,如果你确定自己要新建分支并直接切换过去,可以用一个命令实现:
|
||||
当然,如果你确定自己直接切换到新建的分支,可以用一个命令实现:
|
||||
|
||||
$ git checkout -b feature132
|
||||
|
||||
@ -117,20 +117,20 @@ git的一个超强大的功能就是可以有不止一个远端服务器(实
|
||||
$ git checkout -b twitter-experiment feature132
|
||||
$ git branch -d feature132
|
||||
|
||||
更新:你也可以(像Brian Palmer在原博客文章的评论里提出的)只用“git branch”的-m开关在一个命令里实现(像Mike提出的,如果你只有一个分支参数,就会重命名当前分支):
|
||||
更新:你也可以(像Brian Palmer在原博客文章的评论里提出的)只用“git branch”的-m开关在一个命令里实现(像Mike提出的,如果你只指定了一个分支参数,就会重命名当前分支):
|
||||
|
||||
$ git branch -m twitter-experiment
|
||||
$ git branch -m feature132 twitter-experiment
|
||||
|
||||
#### 8. 合并分支 ####
|
||||
|
||||
在将来什么时候,你希望合并改动。有两种方式:
|
||||
也许在将来的某个时候,你希望将改动合并。有两种方式:
|
||||
|
||||
$ git checkout master
|
||||
$ git merge feature83 # 或者...
|
||||
$ git rebase feature83
|
||||
|
||||
merge和rebase之间的差别是merge会尝试处理改动并建立一个新的混合了两者的提交。rebase会尝试把你从一个分支最后一次分离后的所有改动,一个个加到该分支的HEAD上。不过,在已经将分支推到远端服务器后不要再rebase了 - 这回引起冲突/问题。
|
||||
merge和rebase之间的差别是merge会尝试处理改动并建立一个新的混合了两者的提交。rebase会尝试把你从一个分支最后一次分离后的所有改动,一个个加到该分支的HEAD上。不过,在已经将分支推到远端服务器后不要再rebase了 - 这会引起冲突/问题。
|
||||
|
||||
如果你不确定在哪些分支上还有独有的工作 - 所以你也不知道哪些分支需要合并而哪些可以删除,git branch有两个开关可以帮你:
|
||||
|
||||
@ -147,7 +147,7 @@ merge和rebase之间的差别是merge会尝试处理改动并建立一个新的
|
||||
$ git push origin twitter-experiment:refs/heads/twitter-experiment
|
||||
# origin是我们服务器的名字,而twitter-experiment是分支名字
|
||||
|
||||
更新:感谢Erlend在原博客文章上的评论 - 这个实际上和`git push origin twitter-experiment`效果一样,不过使用完整的语法,你可以在两者之间使用不同的分知名(这样本地分支可以是`add-ssl-support`而远端是`issue-1723`)。
|
||||
更新:感谢Erlend在原博客文章上的评论 - 这个实际上和`git push origin twitter-experiment`效果一样,不过使用完整的语法,你可以在两者之间使用不同的分支名(这样本地分支可以是`add-ssl-support`而远端是`issue-1723`)。
|
||||
|
||||
如果你想在远端服务器上删除一个分支(注意分支名前面的冒号):
|
||||
|
||||
@ -210,7 +210,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
这会让你进入一个基于菜单的交互式提示。你可以使用命令中的数字或高亮的字母(如果你在终端里打开了高亮的话)来进入相应的模式。然后就只是输入你希望操作的文件的数字了(你可以使用这样的格式,1或者1-4或2,4,7)。
|
||||
|
||||
如果你想进入补丁模式(交互式模式下的‘p’或‘5’),你也可以直接进入:
|
||||
如果你想进入补丁模式(交互式模式下按‘p’或‘5’),你也可以直接进入:
|
||||
|
||||
$ git add -p
|
||||
diff --git a/dummy.rb b/dummy.rb
|
||||
@ -226,11 +226,11 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
end
|
||||
Stage this hunk [y,n,q,a,d,/,e,?]?
|
||||
|
||||
你可以看到下方会有一些选项供选择用来添加该文件的这个改动,该文件的所有改动,等等。使用‘?’命令可以详细解释这些选项。
|
||||
你可以看到下方会有一些选项供选择用来添加该文件的这个改动、该文件的所有改动,等等。使用‘?’命令可以详细解释这些选项。
|
||||
|
||||
#### 12. 从文件系统里保存/取回改动 ####
|
||||
|
||||
有些项目(比如git项目本身)在git文件系统中直接保存额外文件而并没有将它们加入到版本控制中。
|
||||
有些项目(比如Git项目本身)在git文件系统中直接保存额外文件而并没有将它们加入到版本控制中。
|
||||
|
||||
让我们从在git中存储一个随机文件开始:
|
||||
|
||||
@ -251,7 +251,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
#### 13. 查看日志 ####
|
||||
|
||||
如果不用‘git log’来查看最近的提交你git用不了多久。不过,有一些技巧来更好地应用。比如,你可以使用下面的命令来查看每次提交的具体改动:
|
||||
长时间使用 Git 的话,不会没用过‘git log’来查看最近的提交。不过,有一些技巧来更好地应用。比如,你可以使用下面的命令来查看每次提交的具体改动:
|
||||
|
||||
$ git log -p
|
||||
|
||||
@ -268,7 +268,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
#### 14. 搜索日志 ####
|
||||
|
||||
如果你想找特定作者可以这样做:
|
||||
如果你想找特定提交者可以这样做:
|
||||
|
||||
$ git log --author=Andy
|
||||
|
||||
@ -278,7 +278,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
$ git log --grep="Something in the message"
|
||||
|
||||
也有一个更强大的叫做pickaxe的命令用来查找删除或添加某个特定内容的提交(比如,该文件第一次出现或被删除)。这可以告诉你什么时候增加了一行(但这一行里的某个字符后面被改动过就不行了):
|
||||
也有一个更强大的叫做pickaxe的命令用来查找包含了删除或添加的某个特定内容的提交(比如,该内容第一次出现或被删除)。这可以告诉你什么时候增加了一行(但这一行里的某个字符后面被改动过就不行了):
|
||||
|
||||
$ git log -S "TODO: Check for admin status"
|
||||
|
||||
@ -294,7 +294,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
$ git log --since=2.months.ago --until=1.day.ago
|
||||
|
||||
默认情况下会用OR来组合查询,但你可以轻易地改为AND(如果你有超过一条的标准)
|
||||
默认情况下会用OR来组合查询,但你可以轻易地改为AND(如果你有超过一条的查询标准)
|
||||
|
||||
$ git log --since=2.months.ago --until=1.day.ago --author=andy -S "something" --all-match
|
||||
|
||||
@ -310,7 +310,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
$ git show feature132@{yesterday} # 时间相关
|
||||
$ git show feature132@{2.hours.ago} # 时间相关
|
||||
|
||||
注意和之前部分有些不同,末尾的插入符号意思是该提交的父节点 - 开始位置的插入符号意思是不在这个分支。
|
||||
注意和之前部分有些不同,末尾的^的意思是该提交的父节点 - 开始位置的^的意思是不在这个分支。
|
||||
|
||||
#### 16. 选择范围 ####
|
||||
|
||||
@ -321,7 +321,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
你也可以省略[new],将使用当前的HEAD。
|
||||
|
||||
### Rewinding Time & Fixing Mistakes ###
|
||||
### 时光回溯和后悔药 ###
|
||||
|
||||
#### 17. 重置改动 ####
|
||||
|
||||
@ -329,7 +329,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
$ git reset HEAD lib/foo.rb
|
||||
|
||||
通常会使用‘unstage’的别名,因为看上去有些不直观。
|
||||
通常会使用‘unstage’的别名,因为上面的看上去有些不直观。
|
||||
|
||||
$ git config --global alias.unstage "reset HEAD"
|
||||
$ git unstage lib/foo.rb
|
||||
@ -369,11 +369,11 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
#### 19. 交互式切换基础 ####
|
||||
|
||||
这是一个我之前看过展示却没真正理解过的很赞的功能,现在很简单。假如说你提交了3次但是你希望更改顺序或编辑(或者合并):
|
||||
这是一个我之前看过展示却没真正理解过的很赞的功能,现在觉得它就很简单了。假如说你提交了3次但是你希望更改顺序或编辑(或者合并):
|
||||
|
||||
$ git rebase -i master~3
|
||||
|
||||
然后会启动你的编辑器并带有一些指令。你所要做的就是修改这些指令来选择/插入/编辑(或者删除)提交和保存/退出。然后在编辑完后你可以用`git rebase --continue`命令来让每一条指令生效。
|
||||
然后这会启动你的编辑器并带有一些指令。你所要做的就是修改这些指令来选择/插入/编辑(或者删除)提交和保存/退出。然后在编辑完后你可以用`git rebase --continue`命令来让每一条指令生效。
|
||||
|
||||
如果你有修改,将会切换到你提交时所处的状态,之后你需要使用命令git commit --amend来编辑。
|
||||
|
||||
@ -446,7 +446,7 @@ git会基于当前的提交信息自动创建评论。如果你更希望有自
|
||||
|
||||
$ git branch experimental SHA1_OF_HASH
|
||||
|
||||
如果你访问过的话,你通常可以用git reflog来找到SHA1哈希值。
|
||||
如果你最近访问过的话,你通常可以用git reflog来找到SHA1哈希值。
|
||||
|
||||
另一种方式是使用`git fsck —lost-found`。其中一个dangling的提交就是丢失的HEAD(它只是已删除分支的HEAD,而HEAD^被引用为当前的HEAD所以它并不处于dangling状态)
|
||||
|
||||
@ -460,7 +460,7 @@ via: https://www.andyjeffries.co.uk/25-tips-for-intermediate-git-users/
|
||||
|
||||
作者:[Andy Jeffries][a]
|
||||
译者:[zpl1025](https://github.com/zpl1025)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](http://linux.cn/) 荣誉推出
|
||||
|
Loading…
Reference in New Issue
Block a user