Friday, February 12, 2016

Git Misc Part 2



http://penandpants.com/2013/02/07/git-pushing-to-a-remote-branch-with-a-different-name/
git: Pushing to a Remote Branch with a Different Name
git push origin local-name:remote-name

https://github.com/isaacs/github/issues/201
As a workaround, search can do it:
克隆版本库的时候,所使用的远程主机自动被Git命名为origin。如果想用其他的主机名,需要用git clone命令的-o选项指定。
$ git clone -o jQuery https://github.com/jquery/jquery.git
$ git remote
jQuery

git remote show命令加上主机名,可以查看该主机的详细信息。

$ git remote show <主机名>

git remote add命令用于添加远程主机。
$ git remote add <主机名> <网址>
git remote rm命令用于删除远程主机。
$ git remote rm <主机名>
git remote rename命令用于远程主机的改名。
$ git remote rename <原主机名> <新主机名>

一旦远程主机的版本库有了更新(Git术语叫做commit),需要将这些更新取回本地,这时就要用到git fetch命令。
$ git fetch <远程主机名>
上面命令将某个远程主机的更新,全部取回本地。
默认情况下,git fetch取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。
$ git fetch <远程主机名> <分支名>
比如,取回origin主机的master分支。
$ git fetch origin master
所取回的更新,在本地主机上要用”远程主机名/分支名”的形式读取。比如origin主机的master,就要用origin/master读取。
git branch命令的-r选项,可以用来查看远程分支,-a选项查看所有分支。
$ git branch -r
origin/master

$ git branch -a* master
  remotes/origin/master
上面命令表示,本地主机的当前分支是master,远程分支是origin/master。
取回远程主机的更新以后,可以在它的基础上,使用git checkout命令创建一个新的分支。
$ git checkout -b newBrach origin/master
上面命令表示,在origin/master的基础上,创建一个新分支。
此外,也可以使用git merge命令或者git rebase命令,在本地分支上合并远程分支。
$ git merge origin/master# 或者
$ git rebase origin/master

git pull命令的作用是,取回远程主机某个分支的更新,再与本地的指定分支合并。它的完整格式稍稍有点复杂。

$ git pull <远程主机名> <远程分支名>:<本地分支名>
比如,取回origin主机的next分支,与本地的master分支合并,需要写成下面这样。
$ git pull origin next:master
如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
$ git pull origin next
上面命令表示,取回origin/next分支,再与当前分支合并。实质上,这等同于先做git fetch,再做git merge。
$ git fetch origin
$ git merge origin/next
在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动”追踪”origin/master分支。
Git也允许手动建立追踪关系。
git branch --set-upstream master origin/next
上面命令指定master分支追踪origin/next分支。
如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名。
$ git pull origin
上面命令表示,本地的当前分支自动与对应的origin主机”追踪分支”(remote-tracking branch)进行合并。
如果当前分支只有一个追踪分支,连远程主机名都可以省略。
$ git pull
上面命令表示,当前分支自动与唯一一个追踪分支进行合并。
如果合并需要采用rebase模式,可以使用–rebase选项。
$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>

五、git push

git push命令用于将本地分支的更新,推送到远程主机。它的格式与git pull命令相仿。
$ git push <远程主机名> <本地分支名>:<远程分支名>
注意,分支推送顺序的写法是<来源地>:<目的地>,所以git pull是<远程分支>:<本地分支>,而git push是<本地分支>:<远程分支>。
如果省略远程分支名,则表示将本地分支推送与之存在”追踪关系”的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。
$ git push origin master
上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。
$ git push origin :master# 等同于
$ git push origin --delete master
上面命令表示删除origin主机的master分支。
如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。
$ git push origin
上面命令表示,将当前分支推送到origin主机的对应分支。
如果当前分支只有一个追踪分支,那么主机名都可以省略。
$ git push
如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
$ git push -u origin master
上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
不带任何参数的git push,默认只推送当前分支,这叫做simple方式。此外,还有一种matching方式,会推送所有有对应的远程分支的本地分支。Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。如果要修改这个设置,可以采用git config命令。
$ git config --global push.default matching# 或者
$ git config --global push.default simple
还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用–all选项。
$ git push --all origin
上面命令表示,将所有本地分支都推送到origin主机。
如果远程主机的版本比本地版本更新,推送时Git会报错,要求先在本地做git pull合并差异,然后再推送到远程主机。这时,如果你一定要推送,可以使用–force选项。
$ git push --force origin
上面命令使用–force选项,结果导致在远程主机产生一个”非直进式”的合并(non-fast-forward merge)。除非你很确定要这样做,否则应该尽量避免使用–force选项。
最后,git push不会推送标签(tag),除非使用–tags选项。
$ git push origin --tags
http://w3cschool.codecloud.net/git/git-high-level-tips.html
$ git config --global user.name "Some One"
$ git config --global user.email "someone@gmail.com"

2. Git是基于指针的

保存在git里的一切都是文件。当你创建一个提交的时候,会建立一个包含你的提交信息和相关数据(名字,邮件地址,日期/时间,前一个提交,等等)的文件,并把它链接到一个树文件中。这个树文件中包含了对象或其他树的列表。这里的提到的对象(或二进制大对象)是和本次提交相关的实际内容(它也是一个文件,另外,尽管文件名并没有包含在对象里,但是存储在树中)。所有这些文件都使用对象的SHA-1哈希值作为文件名。
用这种方式,分支和标签就是简单的文件(基本上是这样),包含指向该提交的SHA-1哈希值。使用这些索引会带来优秀的灵活性和速度,比如创建一个新分支就是简单地用分支名字和所分出的那个提交的SHA-1索引来创建一个文件。当然,你不需要自己做这些,而只要使用Git命令行工具(或者GUI),但是实际上就是这么简单。
你也许听说过叫HEAD的索引。这只是简单的一个文件,包含了你当前指向的那个提交的SHA-1索引值。如果你正在解决一次合并冲突然后看到了HEAD,这并不是一个特别的分支或分支上的一个必需的特殊位置,只是标明你当前所在位置。
所有的分支指针都保存在.git/refs/heads里,HEAD在.git/HEAD里,而标签保存在.git/refs/tags里 – 自己可以随便进去看看。

3. 两个爸爸(父节点) – 你没看错!

在历史中查看一个合并提交的信息时,你将看到有两个父节点(不同于工作副本上的常规提交的情况)。第一个父节点是你所在的分支,第二个是你合并过来的分支。
另一种方式是通过git输出文件 – 你可以输出到另外的文件名,然后当你决定了要用哪个后,再将选定的正确文件复制为正常的文件名:
$ git show master:flash/foo.fla > master-foo.fla
$ git show feature132:flash/foo.fla > feature132-foo.fla
$ # 检出master-foo.fla和feature132-foo.fla
$ # 假如说我们决定来自feature132的文件是正确的
$ rm flash/foo.fla
$ mv feature132-foo.fla flash/foo.fla
$ rm master-foo.fla
$ git add flash/foo.fla
更新:感谢Carl在原博客文章上评论里的提醒,你实际上可以用“git checkout —ours flash/foo.fla”和“git checkout —theirs flash/foo.fla”来检出特定版本的文件,而不用记住你在合并的分支名字。就我个人来说喜欢更精确一点,但这也是一种方式…
$ git remote add john git@github.com:johnsomeone/someproject.git

你随时都可以查看本地分支和远端分支的差异:
$ git diff master..john/master
你也可以查看没有在远端分支上的HEAD的改动:
$ git log remote/branch..

在git里有两种类型的标签 – 轻量级标签和带注释标签。记住技巧2里说过git是基于指针的,这两者之间的差异也很简单。轻量级标签只是一个简单的指向一次提交的带名字指针。你随时都可以将它指向另一个提交。带注释标签是一个指向标签对象的带名字指针,带有自己的信息和历史。因为有自己的信息,它可以根据需要用GPG签名。
建立这两种类型的标签都很简单(只有一个命令行开关的差异)
$ git tag to-be-tested
$ git tag -a v1.1.0 # 会提示输入标签的信息

在git里建立分支非常简单(而且像闪电一样快,因为它只需要创建一个小于100字节的文件)。用普通方式建立新分支并切换过去:
$ git branch feature132
$ git checkout feature132
当然,如果你确定自己直接切换到新建的分支,可以用一个命令实现:
$ git checkout -b feature132
如果你想重命名一个本地分支也很简单(可以显示发生了什么的较长的方式):
$ git checkout -b twitter-experiment feature132
$ git branch -d feature132
更新:你也可以(像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了 – 这会引起冲突/问题。
如果你不确定在哪些分支上还有独有的工作 – 所以你也不知道哪些分支需要合并而哪些可以删除,git branch有两个开关可以帮你:
# 显示已经全部合并到当前分支的分支
$ git branch --merged
# 显示没有合并到当前分支的分支
$ git branch --no-merged

11. 交互式添加

$ git log -p
或者你可以仅仅查看有哪些文件改动:
$ git log --stat
有个很不错的别名你可以试试,会显示简短提交名和一个不错的分支图并在一行里显示提交信息(有点像gitk,但是是在命令行下):
$ git config --global alias.lol "log --pretty=oneline --abbrev-commit --graph --decorate"
$ git lol* 4d2409a (master) Oops, meant that to be in Korean
* 169b845 Hello world

14. 搜索日志

如果你想找特定提交者可以这样做:
$ git log --author=Andy
更新:感谢Johannes的评论,我已经去掉了之前这里的一些有混淆的地方。
或者你想在提交信息里找一些相关字段:
$ git log --grep="Something in the message"
也有一个更强大的叫做pickaxe的命令用来查找包含了删除或添加的某个特定内容的提交(比如,该内容第一次出现或被删除)。这可以告诉你什么时候增加了一行(但这一行里的某个字符后面被改动过就不行了):
$ git log -S "TODO: Check for admin status"
假如你改动了一个特定的文件,比如lib/foo.rb
$ git log lib/foo.rb
比如说你有一个feature/132分支和feature/145分支,然后你想看看这两个分支上不在master分支里的提交(注意符号是不在的意思):
$ git log feature/132 feature/145 ^master
你也可以使用ActiveSupport格式的日期来缩小到某个日期范围:
$ git log --since=2.months.ago --until=1.day.ago
默认情况下会用OR来组合查询,但你可以轻易地改为AND(如果你有超过一条的查询标准)
$ git log --since=2.months.ago --until=1.day.ago --author=andy -S "something" --all-match

15. 查看/修改版本

有很多方式可以用来引用一个版本,看你记得哪个:
$ git show 12a86bc38 # 根据版本
$ git show v1.0.1 # 根据标签
$ git show feature132 # 根据分支名
$ git show 12a86bc38^ # 一次提交的父节点
$ git show 12a86bc38~2 # 一次提交的祖父节点
$ git show feature132@{yesterday} # 时间相关
$ git show feature132@{2.hours.ago} # 时间相关
注意和之前部分有些不同,末尾的的意思是该提交的父节点 – 开始位置的的意思是不在这个分支。

16. 选择范围

最简单的方式:
$ git log origin/master..new

24. 数据维护

通常git不需要经常维护,它把自己照顾的很好。不过,你可以通过下面的命令查看数据统计:
$ git count-objects -v
如果占用很多空间的话,你可以选择在你的本地仓库做垃圾回收。这不会影响推送或其他人,却会让一些命令运行更快而且减少空间占用:
$ git gc
经常运行完整性检查也很有意义:
$ git fsck --full
你也可以在末尾加上–auto参数(如果你在服务器上通过crontab经常/每天都运行这个命令的话),然后它只会在必要的时候才执行fsck动作。
在检查的时候,看到“dangling”或“unreachable”是正常的,通常这是由回退HEAD或切换基础的结果。而看到“missing”或“sha1 mismatch”就不对了…找专业人士帮忙吧!

25. 恢复遗失的分支

如果你使用-D参数删除了experimental分支,可以用下面的命令重新建立:
$ git branch experimental SHA1_OF_HASH
如果你最近访问过的话,你通常可以用git reflog来找到SHA1哈希值。
另一种方式是使用git fsck —lost-found。其中一个dangling的提交就是丢失的HEAD,它只是已删除分支的HEAD,而HEAD被引用为当前的HEAD所以它并不处于dangling状态。

23. 找出谁是凶手

通常找出来谁改动了某个文件里的某行代码会很有用。实现这个功能的最简单命令是:
$ git blame FILE
有时候这些改动来自其他文件(如果你合并了两个文件,或者你移动了某个函数)所以你可以使用下面的命令:
$ # 显示内容来自哪个文件
$ git blame -C FILE
有时候通过点击各个改动然后回到很早很早以前来跟踪改动会很不错。有一个很好的内建GUI命令来做这个:
$ git gui blame FILE


Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts