您的位置:首页 > 其它

Git常用命令

2016-02-29 22:34 417 查看
1、commit提交代码(git commit)

Git 仓库中的一次提交(commit)记录目录下所有文件的快照。感觉像是大量的复制和粘贴,但 Git 做的不只这么简单!

Git 希望提交记录尽可能地轻量,所以每次进行提交时,它不会简单地复制整个目录。实际上它把每次提交记录保存为从

代码库的一个版本到下一个版本的变化集,或者说一个"增量(delta)"。所以,大部分提交记录都有一个父提交(parent commit)

克隆(clone)代码库时,需要解包(unpack)或者“解析(resolve)”所有的差异。提交记录非常轻量且可以快速切换!

2、branch

git branch

Git 的分支非常轻量。它们只是简单地指向某个提交纪录——仅此而已。

使用分支其实就是在说:“我想包含本次提交及所有的父提交记录。”

创建分支没有储存或内存上的开销,所以按逻辑分解工作比维护单一的代码树要简单。

git branch bugFix;git checkout bugFix;git commit;

3、merge

合并两个不同分支的工作。这让我们可以新建一个分支,在其上开发新功能,然后合并回主线。

4、rebase

Rebasing 就是取出一系列的提交记录,"复制"它们,然后把在别的某个地方放下来。

5、head

用不同的方法在代表你的项目的提交记录树上前后移动。

HEAD 是当前提交记录的符号名称 -- 其实就是你正在其基础进行工作的提交记录。

HEAD 总是指向最近一次提交记录,表现为当前工作树。大多数修改工作树的 Git 命令都开始于改变 HEAD 指向。

HEAD 通常指向分支名(比如 bugFix)。

The "~" 操作符

假设需要在提交树中向上移动很多步。使用多个 ^ 非常无聊,所以 Git 也引入了波浪 (~) 操作符。

波浪操作符后面可以(可选地)跟一个数字,指定向上移动多少次。

你可以使用 -f 选项直接让分支指向另一个提交。举个例子:

git branch -f master HEAD~3

(强制)移动 master 指向 HEAD 的第3级父提交。

6、撤销Git里的变动

在 Git 里主要用两种方法来撤销变动 —— 一种是 git reset,另外一种是 git revert。

git reset 把分支记录回退到上一个提交记录来实现撤销改动。你可以认为这是在"重写历史"。git reset 往回移动分支,原来指向的提交记录好像重来没有提交过一样。

虽然在你的本地分支中使用 git reset 很方便,但是这种“改写历史”的方法对别人的远端分支是无效的哦!

为了撤销更改并传播给别人,我们需要使用 git revert。

7、cherry-pick

格式:git cherry-pick <commit1><commit2><...>

这是一种很直接的推进方式 -- 如果你想将一些提交复制到你当前的位置 HEAD 下面.

8、git interactive rebase

如果你知道你所需要的提交对象(相应的 hash), 那用 Git cherry-pick 就非常方便了 -- 很难有简单的方式了

但是如果你不清楚你想要的提交对象的 hash 呢? 幸好 Git 帮你想到了这一点, 我们可以利用交互 rebase -- 如果你想衍合一系列的提交, 这就是最方便的方法了.

交互式 rebase 指的是 rebase 后跟一个参数: -i

git rebase -i HEAD~3

Git 会开启一个 UI 并 展示出将要被复制到目标的提交对象, 它也会显示它们的提交 hash 和信息

真实的 Git, UI 窗口指的是在类似于 Vim 的文本编辑器中打开一个文件.

9、本地栈式提交

git rebase -i HEAD~3

git branch -f master bugFix

10、提交变换戏法

git rebase -i HEAD~2;git rebase -i HEAD~1;git rebase -i HEAD~2;git branch -f master caption

提交变换戏法的第二种方法:

第一种方法要排很多次,有可能造成衍合冲突。另外一种方法 git cherry-pick 是怎么做的吧。

要在心理牢记 cherry-pick 可以从提交树的任何地方拿一个提交来放在 HEAD 上(尽管那个提交不在上游)。

git checkout master; git cherry-pick C2; git commit --amend; git cherry-pick C3;

11、tag

branch 很容易被移动,而且当有新的 commit 时,又会再移动,branch 经常指向不同的 commit,branch 很容易改变。

有没有什么方法可以永远有一个指向 commit 的记号。

git tag 可以解决这个问题,它们可以永远地指向某个特定的 commit,就像是表示一个"里程碑"一样。

更重要的是,当有新的 commit 时,它们也不会移动,你不可以 "checkout" 到 tag 上面 commit,tag 的存在就像是一个在 commit tree 上的表示特定讯息的一个锚。

git tag v0 C1; git tag v1 C2; git checkout v1;

或者可以用:git tag v1 side~1; git tag v0 master~2; git checkout v1;

12、describe

因为 tag 在 commit tree 上表示的是一个锚点,Git 有一个指令可以用来显示离你最近的锚点(也就是 tag),而且这个指令叫做git describe.

当你已经完成了一个 git bisect(一个找寻有 bug 的 commit 的指令),或者是当你使用的是你跑去度假的同事的电脑时, git describe 可以帮助你了解你离最近的 tag 差了多少个 commit。

git describe 的​​使用方式:

git describe <ref>

<ref> 是任何一个可以被 Git 解读成 commit 的位置,如果你没有指定的话,Git 会以你目前所在的位置为准(HEAD)。

指令的输出就像这样:

<tag>_<numCommits>_g<hash>

<tag> 表示的是离 <ref> 最近的 tag, numCommits 是表示这个 tag 离 <ref> 有多少个 commit, <hash> 表示的是你所给定的 <ref> 所表示的 commit 的前七个 id。

13、多分支rebase

呐,现在我们有很多分支啦!让我们 rebase 这些分支的工作到 master 分支上吧。

但是你的头头找了点麻烦 —— 他们希望得到有序的提交历史,也就是我们最终的结果是 C7' 在最底部,C6' 在它上面,以此类推。

git rebase master bugFix; git rebase bugFix side; git rebase side another;

git branch -f master another;

14、选择父提交

使用 ^ 和 ~ 可以自由地在提交树中移动。这些修改符支持链式操作!git checkout HEAD~^2~2

git checkout HEAD~^2~1; git branch bugWork; git checkout master;

或者可以直接用如下语句搞定:git branch bugWork master^^2^;

15、分支浆糊

git checkout one; git cherry-pick C4 C3 C2;git checkout two;git cherry-pick C5 C4 C3 C2;

git branch -f three C2;

Git remote远程操作仓库中的代码,与别人共享

1、clone


首先, 远程仓库是一个强大的备份. 本地仓库也有恢复文件的能力, 但所有的信息都是保存在本地的. 即使你丢失了本地数据, 你仍可以通过远端仓库拷贝拿回你丢失的数据。

更重要的是, 远端让代码社交化了! 现在你的项目被拷贝到别的地方了, 你的朋友可以更容易的为你的项目做贡献(或者 pull 最新的变更)。

现在使用网站来可视化远端仓库变得越发流行(像 Github or Phabricator), 但远程仓库是这些工具的基石。

git clone会在本地创建一个远端仓库的拷贝。

2、git远端分支

3、fetch (从远端仓库获取数据)


当我们更新远端的仓库时, 我们的远端分支也会更新 并映射到最新的远端仓库.

git fetch 完成了两步:

下载本地仓库未包含的提交对象

更新我们的远端分支点(如, o/master)

git fetch 实际上将本地对远端的映射 做了同步更新

如果你还记得之前的课程, 我们说过远端分支映射了远端仓库的状态(你最后与远端通信的那一刻), git fetch 是你与远端交流的方式!

git fetch 通常通过互联网(像 http:// or git://) 与远端仓库通信.

git fetch, 不能改变你的本地状态. 你不会更新你的 master 或者 任何与文件系统相关的东西.

所以, 你可以将git fetch 的执行 视为下载。

4、pull

现在我们已经知道了如何用 git fetch 获取远端的变化, 现在我们学习如果将这些变化更新到我们的工作.

其实有很多方法的 -- 只要我在本地有新的提交, 你可以像合并其它分支那样合并远端分支. 具体说就是你可以执行以下命令:

git cherry-pick o/master

git rebase o/master

git merge o/master

etc, etc

实际上, fetch / merge 变更是这样的普通, 以至于git 提供了一个实际两个功能的命令 -- git pull.

git pull 是git fetch和git merge的缩写。

克隆一个远端,再提交一些修改,在你自己的分支上也做一些提交,再 pull 一下远端。

git clone;git fakeTeamwork master2;git commit; git pull;

5、push

上传与别人分享

git push 负责将你的提交上传到远端, 一旦 git push 完成, 你的朋友就可以在远端下载你的工作了!

git clone;git commit; git commit; git push;

6、远端库历史的分散

想象一下你周一克隆了一个仓库, 然后在一个特性分支上工作. 到周五时, 你准备推送你的特性分支 -- 不行的! 你的同事这周写了一堆代码, 使得你的特性分支过期了. 他们已经将代码分享(合并)到远端仓库了, 所以你的工作就变成了基于仓库老版的代码了.

这种情况下, git push 就变得模糊了, 如果你执行 git push, Git 应该让远端仓库回到星期一那天? 还是直接在新代码的基础上添加你的代码? 或者直接忽略你的提交?

因为这情况让问题变得模糊(因为历史的分散性)了, Git 不会允许你 push. 你只能先合并远端最新的代码, 然后才能分享你的工作.

如何解决这事儿呢? 很简单, 你需要做的就是使你的工作基于最新的远端分支。最直接的方法就是通过 rebase 修订你的工作。

此外,merge也可以实现此功能。不同的是,rebase会转移你的工作,而merge不会转移你的工作,但它会创建新的合并提交,它会告诉 Git 你已经合并了远端的所有变更 -- 远端分支就是你自己分支的祖先, 这意味着, 你的提交反映了远端分支的提交。

git pull --rebase 就是 fetch 和 rebase 的简写!

以下两种的写法效果是一样的:

(1)git fetch;git rebase o/master;git push;

(2)git pull --rebase; git push;

以下两种的写法效果是一样的:

(1)git fetch;git merge o/master; git push;

(2)git pull; git push;

7、合并特性分支push master

开发者只在 master 上做 push/pull —— 这样的话 master 总是最新的,即与远端 (o/master) 一致。

这里有三个特性分支 -- side1 side2 和 side3

我需要按顺序将这三分支推送到远端.

因为远端已经被更新过了, 所以我们需要先做合并。

8、远端跟踪

长话短说, master 和 o/master 的连接关系就是 分支属性"remote tracking" (我们叫远端跟踪好啦). master 被设定为跟踪 o/master --

这就是隐含的合并(merge)/推送(push)目的地.

你可能想知道这个属性是怎么被设定的? 你并没有用命令指定过这个属性呀! 好吧, 当你克隆仓库的时候, 这个属性就存在了.

当你克隆时, Git 会创建跟踪分支(就像 o/master), 对于每个远端分支, 创建一个跟踪远端分支的本地分支 (master), 所以你经常会看到这个的命令输出:

local branch "master" set to track remote branch "o/master"

我能自己指定这个属性吗?

当然可以啦! 你可以让做任意分支跟踪 o/master, 然后分支就会隐含 push 的 destination(o/master) 以及 merge 的 target (o/master).

这意味着你可以在分支 totallyNotMaster 上执行 git push, 将工作推送到远端的 master.

有两种方法设置这个属性,:

第一种就是通过远端分支检出一个新的分支, 执行:

git checkout -b totallyNotMaster o/master

这样就创建了一个跟踪 o/master 的 新分支 totallyNotMaster.

方法#2

另一种追踪远端分支的方法就是使用选项 : git branch -u .

git branch -u o/master foo

这样 foo 就会跟踪 o/master 了. 如果你处于 foo 分支, 那么可以省略 foo

git branch -u o/master

本节我们在不检出 master 的情况下将工作推送到的远端的 master。

git fetch

$ git commit

$ git rebase o/master master

$ git push

$ git branch side

$ git branch -f master HEAD~2

git checkout side;

git checkout -b side o/master; //local branch "side" set to track remote branch "o/master"

git commit;

git pull --rebase;

git push;



9、push的参数

在远端跟踪分支中, 你学到了 Git 会找出要 push 的目的地(通过查看检出的分支, 及分支关联到的跟踪分支).

这是无参数的行为, 不过我们也可以为 push 指定参数:

git push <remote> <place>

git push origin master

切到 master 分支, 然后抓取所有的提交, 再将新提交推送到远端的 master 分支!

通过指定 master 为 <place> 参数, 我们告诉 Git 提交来自于 master, 要推送到远端的 master. 这种使用方式基本上用于同步两仓库

谨记, 因为我们通过指定参数告诉了 Git 所有的事, Git 就忽略了我们所检出的分支(转而直接使用参数指定的分支作为 source/destination)

本节, 我们要更新远端的 foo 和 master, 在本节中 git checkout 是被禁用的!

当为 git push 指定 master 为 place 时, 我们可以设置 要提交的来源 和 提交到目的地.

你可能想知道 -- 如果来源和目的地不一样呢?

要为 <place> 指定 source 和 destination, 只需要用冒号 : 将二者联结.

git push origin <source>:<destination>

这通常被称为 <colon refspec>, refspec 是一个奇特的名 -- 用于 Git 能识别的位置(比如分支 foo 或者 HEAD~1)

一旦你指定了独立的来源和目的地, 你就可以得到花哨而精确的远程命令.

如果你要 push 到的 destination 不存在呢? 没问题! Git 会在远端为你创建这个分支!

git push origin master^:foo;git push origin foo:master;

10、fetch的参数

git push 的参数, 特别是 <place> 参数, 更特别的冒号分隔(<source>:<destination>). 这些参数同样可以用于 git fetch.

git fetch 的参数和 git push 相当相似. 都是相同的概念, 但是方向相反(因为现在你是下载 而非上传)。

git fetch origin foo

Git 会来到远端的 foo 分支, 然后抓取所有不在本地的新提交, 放到本地的分支 o/foo

我们看看这个动作(这像是更新器)。

如果我们设定了 <source>:<destination> 会发生什么呢?

如果你觉得直接更新本地分支很爽, 那你就用冒号 refspec 吧. 不过, 你不能在检出的分支上干这个事.

这里只有一个特点 -- source 是远端的位置, 而 <destination> 是要放置提交的本地位置, 这真是有趣 -- 这也是传送数据的对立方向!

话虽如此, 开发者很少这么做. 我已经介绍了, 概念上 fetch/push 很相似, 只是它们方向相反.

如果 git fetch 没有参数, 它会下载所有远端分支.

git fetch origin master^:foo;

git fetch origin foo:master;

git checkout foo;

git merge master;

有两种罕见的情况, Git 不需要 <source>. 这基于这样一个事实 -- 技术上说就是你不指定 <source>. 这是通过空参数实现的

git push origin :side;

git fetch origin :bugFix;

如果给 push 传一个空参数会如何呢? 远端会删除分支!

如果给 fetch 传空 <source>, 那本地会创建一个新分支.

[b]11、pull的参数

[/b]

[b]因为 git pull 就是 fetch 后跟 merge 的缩写. 我可以认为执行 git fetch 用了相同的参数, 然后再 merge 你所 fetch 的提交 (commit)。

以下命令在 Git 中是等价的:

git pull origin foo 相当于:

git fetch origin foo; git merge o/foo

还有...

git pull origin bar~1:bugFix 相当于:

git fetch origin bar~1:bugFix; git merge bugFix

看到了? git pull 实际上就是 fetch + merge 的缩写, git pull 在乎的是提交在哪里结束(也就是 git fetch 所确定的 destination)。

作业:

请获取虚拟目标. 你需要下载一些提交, 然后创建一些新分支, 再合并这些分支到其它分支。

git pull origin bar:foo;

git pull origin master:side;

[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: