成大事不在于力量的大小,而在于能坚持多久。 ——约翰生
在日常开发中,我们可能会使用多个帐号以及多个 SSH-Key ,可能是 码云,也可能是 GitHub ,如果你的电脑中只配置了一个 SSH-Key ,那到时候另一个或多个帐号在使用上,就会带来些许不便。(你能忍受每次 push 都要求你输入密码吗?或者每次切换帐号都需要重新配置 SSH-Key 吗?因为每次使用默认配置的方法都会将前一次配置覆盖。),作为程序员,怎么能让这种事情发生呢,我们需要一种一劳永逸的解决办法。经过上网搜索及筛选,我找到一种比较简单方便的方法。
首先你得安装 git 客户端。Windows 平台,安装完后,在桌面右键选择 git bash 打开。Mac 平台安装好,打开 Terminal 或者 iTerm 输入以下命令。
$ ssh-keygen -t rsa -C "[email protected]"
在 Git Bash 中执行命令一路回车,会在 ~/.ssh/ 目录下生成 id_rsa 和 id_rsa.pub 两个文件用文本编辑器打开 id_rsa.pub 里的内容,在 Github 中添加 SSH Keys
接着上一步,为了区分开不同的 SSH-Key,我在生成文件的时候用了不同的名称来区分。 输入你要配置的另一个 SSH-Key 的邮箱。
$ ssh-keygen -t rsa -C "[email protected]"
这次不要一路回车,请输入这个文件的名字,见下面的第三行。
$ ssh-keygen -t rsa -C "[email protected]"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/nimon/.ssh/id_rsa): other
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in other.
Your public key has been saved in other.pub.
The key fingerprint is:
SHA256:tlHc9GiN8cLngDw8QmomMlxmc+2odsRciMjIu6ljjzQ 824291045@qq.com
The key's randomart image is:
+---[RSA 2048]----+
|.o .=..o. o |
|.oo+.o.oo+ = B |
如上输入 other
之后会在.ssh目录下生成两个文件 other
和 other.pub
,原理同步骤1。
因为 SSH-Key 有一个默认的配置,如果我们还是按照默认配置,那么注定是不会成功的。
我们需要在 ~/.ssh 目录下添加 config 配置文件用于区分多个 SSH-Key 。
Host github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa
Host other.github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/other
之后保存并推出编辑器。
publickey,password publickey,keyboard-interactive
,在这里使用 publickey 即可。以上完成之后,在命令行中输入 ssh -T [email protected]
(xxx 就写刚才在配置文件中 Host 后面的名字)与远程进行验证,验证成功就会显示如下信息。
$ ssh -T git@github.com
Hi SmartJunNi! You've successfully authenticated, but GitHub does not provide shell access.
$ ssh -T [email protected]
ssh [email protected]
Hi junoni! You've successfully authenticated, but GitHub does not provide shell access.
如果在项目中使用 git push
时提示[remote reject] (Permission denied)
。如下所示
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 252 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To other.github.com:junoni/nimon.git
! [remote rejected] master -> master (permission denied)
error: failed to push some refs to '[email protected]:junoni/nimon.git'
我花了一个半小时从 google 到 stackoverflow 查了个边,就差没有百度一下了,就是没有找到可以解决的办法。这时我发现最后一行的[email protected]:junoni/nimon.git
这个地址,我想了想,刚刚配置了 config 这个文件,其中Host
使用的是 other.github.com
,我用 git remote -v
查看了当前远程仓库的 origin 。
$ git remote -v
origin git@github.com:junoni/nimon.git (fetch)
origin git@github.com:junoni/nimon.git (push)
可以看到,fetch 和 push 的 origin 地址都是 [email protected] ,而不是 [email protected] ,我就抱着试试的心态,改成了 [email protected]。还有一个步骤,将 other
加入到密钥列表中。
$ ssh-add ~/.ssh/other
再尝试 push 一下,没想到成功了。如迈克尔•乔丹所说:“我可以接受失败,但我不能接受放弃。”
当然,添加之后我们还可以查看当前密钥列表。也可以删除密钥。
$ ssh-add -l
$ ssh-add -d ~/.ssh/other
类似debug,查看与远程连接情况。
$ ssh -v git@github.com
总结:我们设置的远程仓库的地址必须和 config 文件中设置的域名映射地址相同,不然就会出现错误。
mac 下在~/.gitconfig 文件中配置 git 的全局信息。使用 git config --list
可以列出全局配置信息。
$ git config --list
用户信息
配置你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录:
$ git config --global user.name “youname”
$ git config --global user.email “12345@example.com”
如果用了 –global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 –global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。
查看配置信息
查看已有的配置信息
$ git config --list
$ git config -l
获取帮助
例如想获取config命令的帮助信息
$ git help config
$ git config --help
初始化新仓库
$ git init
初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。不过目前,仅仅是按照既有的结构框架初始化好了里边所有的文件和目录,但我们还没有开始跟踪管理项目中的任何一个文件。
如果当前目录下有几个文件想要纳入版本控制,需要先用 git add 命令告诉 Git 开始对这些文件进行跟踪,然后提交:
跟踪文件:(将文件加到暂存区域)
$ git add readme.txt
跟踪全部文件
$ git add .
提交更新
$ git commit -m “first version”
上传(推送)到github
$ git push origin master
从现有仓库克隆
$ git clone git://github.com/youname/project.git
$ git clone git@github.com:youname/project.git
$ git clone https://github.com/youname/project.git
检查当前文件状态
$ git status
创建.gitignore文件
$ touch .gitignore
查看修改之后没有暂存起来的内容
$ git diff
移除文件
$ git rm readme.txt
重命名文件
$ git mv oldname.txt newname.txt
查看提交历史
$ git log
取消暂存
$ git reset HEAD readme.txt
添加远程仓库(远程仓库必须先在github上建好)
$ git remote add [shortname] [url]
实例:
$ git remote add origin git@github.com:youname/yourRepo.git
推送数据到仓库
$ git push [remote-name] [branch-name]
如果要把本地的 master 分支推送到origin服务器上(再次说明下,克隆操作会自动使用默认的master 和origin 名字),可以运行下面的命令:
$ git push origin master
从远程仓库抓取数据
$ git fetch [remote-name]
碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码,那么需要移除对应的远端仓库
远程仓库的删除
$ git remote rm origin
远程仓库重命名(此处命名的是上文添加远程仓库中的shortname)
$ git remote rename origin origin2
自动补全
输入命令后按tab键,就会看到列出所有匹配的可用命令建议:
$ git co
创建一个名为“testing”的分支
$ git branch testing
切换到“testing”分支(默认为master分支)
$ git checkout testing
新建并切换到该分支
$ git checkout -b iss53
这条命令相当于执行下面这两条命令
$ git branch iss53
$ git checkout iss53
删除hotfix分支(如果该分支还未被合并则会提示错误,因为这样会丢失数据)
$ git branch -d hotfix
强制删除hotfix分支(强制删除,不会提示错误)
$ git branch -D hotfix
合并iss53分支(先切换到master分支)
$ git checkout master
$ git merge iss53
查看当前所有分支
$ git branch
查看各个分支最后一个提交对象的信息
$ git branch -v
查看已经与当前分支合并的分支(已经合并的查出来后可以删掉)
$ git branch --merge
查看未与当前分支合并的分支
$ git branch --no-merged
同步远程服务器数据到本地
$ git fetch origin
从新添加的远程仓库下载数据
$ git remote add teamone git://git.team1.ourcompany.com
$ git fetch teamone
分化一个新的分支(使用这个命令会从服务器上下载master最新的版本,所以如果当前本地版本不是最新的,新的分支和本地分支会不同)
$ git checkout -b test1 origin/master
假如你用这个新的分支进行git push,并且通过了合并,那么会在远程仓库建立一个新的同名分支
删除该分支的方法
$ git push origin :test1
分支的衍合:将test1分支衍合到master主分支
$ git checkout test1
$ git rebase master
另一种方法,直接衍合,不用再先切换到test1
$ git rebase master test1
快进master分支
$ git checkout master
$ git merge client
git remote -v
;git push origin branch-name
,如果推送失败,先用git pull
抓取远程的新提交;git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致;git branch --set-upstream branch-name origin/branch-name
;git pull
,如果有冲突,要先处理冲突。找到历史提交的commit ID
git log --graph --pretty=oneline --abbrev-commit
小结
git tag
用于新建一个标签,默认为HEAD
,也可以指定一个commit id;git tag -a -m "blablabla..."
可以指定标签信息;git tag -s -m "blablabla..."
可以用PGP签名标签;git tag
可以查看所有标签。git show
可以查看标签的详情小结
git push origin
可以推送一个本地标签;git push origin --tags
可以推送全部未推送过的本地标签;git tag -d
可以删除一个本地标签;git push origin :refs/tags/
可以删除一个远程标签git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
touch readme.md
刚开始,你需要选择一个目录,开始一个新的 repository。使用以下命令可以在当前目录下初始化 Git 。
git init
git status 查看仓库的状态
git add 向暂存区中添加文件
git commit 保存仓库的历史记录
记录一行提交信息
$ git commit -m "First Commit"
请不要加-m,直接执行 git commit 命令。
$ git commit
+git tracks changes of files.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch dev
# Your branch is ahead of 'origin/dev' by 3 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: readme.md
#
在编辑器中记录提交信息
在以 # 标位注释的 Changes to be committed 可以查看本次提交中包含的文件。其他信息不必修改。
请将提交信息留空并直接关闭编译器,随后提交就会被中止。
Aborting commit due to empty commit message.
执行完git commit 命令后再来查看当前状态
$ git status
On branch dev
nothing to commit, working tree clean
当前工作树处于刚刚提交的最新状态,所以结果显示没有更改。
可以查看以往仓库中提交的日志。包括什么人在什么时候进行了提交或合并,以及操作后有怎样的差别。
$ git log
commit d97ade219a7f50f61790a14aa40f3142a07f49ba
Author: SimpleLifee <824291045@qq.com>
Date: Sat May 20 16:47:09 2017 +0800
First Commit
Commit 旁边显示的是这个提交的哈希值。这个值很重要,在后面会讲到。
Author 栏中显示的是我们给 Git 设置的用户名和邮箱。
Date 栏显示的是提交的日期和时间。
最后是提交信息。
在 git log
后面加上 --pretty=short
$ git log --pretty=short
commit d97ade219a7f50f61790a14aa40f3142a07f49ba
Author: SimpleLifee <824291045@qq.com>
First Commit
在 git log
后加上文件名或者目录名即可。
如果想查看提交所带来的改动,可以加上 -p
参数,文件的前后差别就会显示在提交信息之后。
$ git log -p
只查看某个文件提交前和提交后的差别
$ git log -p README.md
如上, 我们不必依次记下全部参数,每当有想查看的日志就积极去查,慢慢就能得心应手了。
$ git log --stat
git diff
可以查看工作树、暂存区、最新提交之间的差别。
注意暂存区是指 git add
之后,但未 git commit
时保存在暂存区的内容。这个时候可以使用 git diff
来查看工作树和暂存区的差别。
$ git diff readme.md
diff --git a/readme.md b/readme.md
index 7f612d5..c4123d2 100644
--- a/readme.md
+++ b/readme.md
@@ -11,5 +11,5 @@ dev: other
something happend.
i will be fine.
hah
-
+hey! Git!
注意,这里的 +
标出的是新添加的行,被删除的行则用 -
标出。
这时候如果使用 git add
将 README.md
加入暂存区后。工作树和正常启动内容并无差别,结果什么都不会显示。
$ git add README.md
当使用git add
将 README.md
加入暂存区后,要查看工作树与最新提交的差别,请使用以下命令。
$ git diff HEAD
diff --git a/readme.md b/readme.md
index 7f612d5..c4123d2 100644
--- a/readme.md
+++ b/readme.md
@@ -11,5 +11,5 @@ dev: other
something happend.
i will be fine.
hah
-
+hey! Git!
不妨养成这样一个好习惯,在执行 git commit
命令之前先执行 git diff HEAD
查看本次提交与上次提交之间有什么差别,等确认完毕再进行提交。这里的 HEAD
指当前分支中最新的一次提交的指针。
这个命令会将本地的分支名列表显示,* 表示当前所在分支。
$ git branch
* master
以当前分支为基础创建新的分支,可以使用 git checkout -b
命令
执行下面的命令,创建名为 feature-A
$ git checkout -b feature-A
Switched to a new branch 'feature-A'
实际上,以上语句等同于
$ git branch feature-A
$ git checkout feature-A
$ git checkout master
$ git checkout -
使用 -
(连字符) 代替分支名。
顾名思义,特性分支是集中实现单一特性(主题),除此之外不进行任何作业的分支。在日常开发中,往往会创建数个特性分支,同时再保留一个随时可以发布软件的稳定分支。稳定分支一般由 master
分支担当。
只要保持这样一个开发流程,就能保证master分支可以随时供人查看。其他开发者也可以放心大胆从master分支创建新的特性分支。
特性分支的原点,也是合并的终点。主干分支没有开发到一半的代码,可以随时供人查看。
主干分支可以有多个,使用 Tag 标签创建版本信息。
先切换到master,然后与 feature-A
合并
$ git merge --no-ff feature-A
可以直观地用图表形式输出提交的日志。
$ git log --graph
* commit 685c45a39c33a4777d14fb29f6f0bfb9b9920c49
|\ Merge: 6b15d42 40befaa
| | Author: SimpleLifee <[email protected]>
| | Date: Sat May 20 18:04:48 2017 +0800
| |
| | merge
| |
| * commit 40befaab3f0db6fd47e2d553b88428a4ca39e670
| |\ Merge: a0b10f9 6b15d42
| |/ Author: SimpleLifee <[email protected]>
|/| Date: Sat May 20 17:51:52 2017 +0800
| |
| | fix
| |
回溯到创建 feature-A
分支前
让仓库的HEAD、暂存区、当前的工作树回溯到指定状态。
$ git reset --hard <哈希值>
创建 fix-B 分支
推进至feature-A分支合并后的状态
首先回复到feature-A分支合并后的状态,可以称之为“推进历史”。
git log
只能查看以当前状态为终点的历史日志。
所以这里要使用git reflog
查看当前仓库的操作历史, 可以看到commit、checkout、reset、merge等Git命令的执行记录。
如果系统提示我们文件发生了冲突,那么不解决冲突就无法完成合并,所以需要我们手动来解决冲突。解决完冲突文件后再执行git add
和git commit
。
git commit --amend
在合并特性分支之前,如果发现已提交的内容中有些拼写错误,不妨提交一个修改,然后将这个修改包含到前一个提交之中,压缩成一个历史记录。这是个会经常用到的技巧。
首先创建 feature-C 分支,然后 add 和 commit命令。
但是没必要每次这么麻烦。
$ git commit -am "Add feature-C"
执行上面语句的前提是,当前工作树中没有新增的Untracked 的文件。
修改错误之后,使用git diff
来查看差别。
$ git diff
diff --git a/readme.md b/readme.md
index 10f9ebb..3bbe2d0 100644
--- a/readme.md
+++ b/readme.md
@@ -1,2 +1,3 @@
C
C
+fix C
然后进行提交
$ git commit -am "Fix Typo"
[C c3955c1] Fix Typo
1 file changed, 1 insertion(+)
错字漏字等失误称作typo,但是我们不希望在历史记录中看到这类提交,因为健全的历史记录不需要它们。
我们将修正的内容与之前的一次提交合并,在历史记录中合并为一次完美的提交。
$ git rebase -i HEAD~2
上面的命令,可以选定当前分支中包含HEAD ( 最新提交 ) 在内的两个最新历史记录为对象,并在编辑器中打开。
pick 695471a Add C
pick 2f8a965 fix typo
# Rebase 1db92da..2f8a965 onto 1db92da (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
695471a我们将 2f8a965
的 fix typo
的历史记录压缩到 695471a
的 Add C
里。按照下图所示,将2f8a965
左侧的 pick
部分删除,改写为 fixup
。
pick 695471a Add C
fixup 2f8a965 fix typo
保存编译器里的内容,关闭编辑器
[detached HEAD 5f770a9] nnnnnnnn
Date: Sat May 20 22:07:28 2017 +0800
1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/C.
系统显示 rebase 成功,也就是以下面这两个提交作为对象,将 fix typo
的内容合并到了上一个提交Add C
之中,改写成一个新的提交。
现在查看提交日志时会发现 Add C
的哈希值以及不再是 695471a
,这证明提交已经被更改了。
$ git log --graph --oneline
* 5f770a9 Add C
* 1db92da haha
* c1aabf4 Add B
...
这样,fix typo
就从历史中被抹去了,也相当于 Add C
从来没有出现过拼写错误。这算是一种良性的历史改写。
C 分支的使命告一段落,我们将它与master分支合并。
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff feature-C
Merge made by the 'recursive' strategy.
a | 2 ++
readme.md | 2 ++
2 files changed, 4 insertions(+)
create mode 100644 a
create mode 100644 readme.md
按照递归策略合并。
建议在新建远程仓库的时候不要勾选自动生成README文件的选项。
我们用 git remote add
命令将它设置成本地仓库的远程仓库。
$ git remote add origin git@github.com:9981NAN/9981NAN.git
这样,Git会自动将 [email protected]:9981NAN/9981NAN.git
远程仓库名称设置为 origin ( 标识符 )
像上面 git remote add origin
添加第一个URL之后,如果想要添加多个 URL 地址,那么可以使用git remote set-url --add origin
添加第二个URL。
$ git remote set-url --add origin git@github.com:9981NAN/9981NAN.git
这样一来,以后每次 git push origin master
的时候,就会自动向多个远程仓库中推送了。
但是使用 git pull 时,只能拉取origin里的一个URL地址(即fetch-url,如上),这个 fetch-url 默认是你添加到origin 的第一个地址。
如果你想更改,只需要更改 config 文件里,那几个url的顺序即可。 fetch-url 会直接对应排行第一的那个url 链接。
如果想把当前分支下本地仓库的内容推送给远程仓库,需要用到 git push
,假定我们在master分支下
$ git push -u origin master
-u
参数可以在推送的同时,将origin仓库的master分支设置为本地仓库当前分支的 upstream(上游)。这样一来,下次运行 git pull
命令从远程仓库获取内容时,本地仓库这个分支就可以直接从origin 的master 分支获取内容,省去了另外添加参数的麻烦。
创建其他分支
$ git checkout -b feature-D
将它push给远程仓库,并保持分支名不变
$ git push -u origin feature-D
假设现在有另一名开发者要来共同开发,在另一个目录下新建本地仓库。
$ git clone git@github.com:9981NAN/9981NAN.git
注意clone的目录不要与之前操作的仓库在同一目录下
执行 git clone
命令后我们会默认处于master分支下,同时系统会自动将origin设置成该远程仓库的标识符。
我们可以使用下面的命令查看本地仓库和远程仓库的分支信息。
$ git branch -a
我们试着将feature-D分支获取至本地仓库。
$ git checkout -b feature-D origin/feature-D
-b
参数后面是本地仓库中新建分支的名称,可以与远程仓库不同名,但是建议同名,便于理解。
假定我们是另一位开发者,要做一个新的提交。在修改文件内容后进行查看和提交。
$ git diff
$ git commit -am "Add feature-D"
在feature-D
分支下直接使用 git push
即可
$ git diff
回到我们刚刚放下操作的目录,这边的本地仓库中只是创建了feature-D分支,并没有在feature-D进行任何提交,而远程仓库已经有了我们刚刚推送的提交。这时候就可以用git pull
,将本地的 feature-D 分支更新到最新状态。
$ git pull origin feature-D
如果两人同时修改了同一部分的源代码,push时就很容易发生冲突。所以多名开发者在同一个分支中进行作业时,为了减少冲突的情况,建议更频繁地进行push和pull操作。
在仓库页面按下键盘T 键,然后输入要找的文件或者目录。速度非常快。
以我的9981NAN项目为例,要比较nimon分支和yong分支的差别,可以直接在浏览器URL中输入:
https://github.com/9981NAN/9981NAN/compare/nimon...yong
这样就可以查看两个分支间的差别了。
输入下面的URL就可以查看nimon分支最近7天内的差别了。
https://github.com/9981NAN/9981NAN/compare/nimon@{7.day.ago}...nimon
类似的还有
https://github.com/9981NAN/9981NAN/compare/nimon@{2017-05-19}...nimon
在项目的Issue一览表中,每一个Issue标题的下面部分都分配 “#18” 的编号。我们只要在描述信息中加入 “#18” ,就可以在Issue中显示该提交的相关信息,使关联的提交一目了然。
如果一个处于 Open 状态的 Issue 已经处理完毕,只要在该提交中以下列任意一种格式描述提交信息,对应的 Issue 就会被 close 。
这样我们每次提交并push之后,就不必每次都到 Issue 中寻找相应的 Issue 再手动关闭了。这是一项很实用的功能。
Issue 和 Pull Request 的编号通用。
引用评论,选中别人的评论后按 R 键。
在评论中应用表情,输入 “ :” 即可选择。
默认情况下,系统会将空格的不同也高亮显示,想要关闭之? 在URL 的末尾添加 “ ?w=1 ” 就可以不显示空格的差异了。
将鼠标放到被更改行号的左侧,可以看到一个加号,我们可以点击这个加号在代码中插入评论。这样评论是针对哪行代码就一目了然了
Pulse是体现该仓库软件开发活跃度的功能,近期仓库创建了多个pull request 或 Issue,有多少人参与了这个仓库的开发。用户可以判断目前这个人间是否正在积极开发,在挑选GitHub上开发的软件时,可以作为一个重要的衡量标准。
前面两步完成之后,我们需要在特性分支中进行开发
$ git br -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
在 work
之后加上 master
表明在 master
分支的基础上创建 work
分支。
$ git checkout -b work master
Switched to a new branch 'work'
在 readme.md
文件中添加要增加的代码。
$ git commit -am "Add pull request"
[work f3d798e] Add pull request
1 file changed, 1 insertion(+), 2 deletions(-)
把在本地创建的分支推送到远程仓库,如果远程仓库没有该分支,那么就创建之。
$ git push origin work
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 283 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:junoni/nimon.git
* [new branch] work -> work
前提是拥有这个仓库编辑的权限
Fork 或者 clone 来的仓库,一旦放置不管就会离最新的源代码越来越远。这时候我们需要让本地仓库与源代码保持最新状态。
我们需要将原仓库设置为远程仓库,从该仓库获取fetch
数据与本地仓库进行合并 merge
。
$ git remote add upstream git@github.com:SimpleLifee/nimon.git
这样,我们这个仓库将以upstream作为原仓库的标识符。这个环境下只需要设定一次。
可以下面的命令查看
$ git remote -v
origin git@github.com:junoni/nimon.git (fetch)
origin git@github.com:junoni/nimon.git (push)
upstream git@github.com:SimpleLifee/nimon.git (fetch)
upstream git@github.com:SimpleLifee/nimon.git (push)
要让仓库维持最新状态,只需要重复这一工作即可。
$ git fetch upstream
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 14 (delta 3), reused 14 (delta 3), pack-reused 0
Unpacking objects: 100% (14/14), done.
From github.com:SimpleLifee/nimon
* [new branch] dev -> upstream/dev
* [new branch] feature-A -> upstream/feature-A
* [new branch] master -> upstream/master
$ git remote add PR发送者 git@github.com:junoni/nimon.git
查看添加后的情况
$ git remote -v
PR发送者 git@github.com:junoni/nimon.git (fetch)
PR发送者 git@github.com:junoni/nimon.git (push)
origin git@github.com:SimpleLifee/nimon.git (fetch)
origin git@github.com:SimpleLifee/nimon.git (push)
接着进行fetch
$ git fetch PR发送者
remote: Counting objects: 32, done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 32 (delta 14), reused 26 (delta 8), pack-reused 0
Unpacking objects: 100% (32/32), done.
From github.com:junoni/nimon
* [new branch] dev -> PR发送者/dev
* [new branch] master -> PR发送者/master
* [new branch] work -> PR发送者/work
现在我们获取了Pull Request 发送仓库以及分支的数据(PR发送者/work)
前面我们只获取了远程仓库的数据,这些数据尚未反映在任何一个分支中。因此我们需要创建一个分支,用于模拟采纳 Pull Request 后的状态。由于这是我们第一个 Pull Request ,分支名就叫 pr1
。
$ git checkout -b pr1
Switched to a new branch 'pr1'
下面要将已经 fetch 完毕的 “PR发送者/work ” 的修改内容与 pr1
分支进行合并
$ git merge PR发送者/work
这时候我们需要检查一下合并的情况。
检查结束后pr1
分支就没用了,可以直接删除。我们需要先切换到 pr1
之外,例如 master
$ git checkout master
Previous HEAD position was f3d798e... Add pull request
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 12 commits.
(use "git push" to publish your local commits)
这时候,Git 提醒我们当前 master
分支已经比远程仓库多出 12 个新提交了,并建议我们使用 git push
向远程仓库推送新的提交。
之后我们进行删除分支。
$ git branch -D pr1
Deleted branch pr1 (was 685c45a).
我们可以打开浏览器找到相应的 Pull Request 页面,点击 merge pull request按钮,随后Pull Request的内容就会自动合并至仓库。
不过我们已经在本地构筑了相同的环境,只要通过 CLI 进行合并操作后再 push 至 Github,就可以完成Pull Request。
首先我们切换到 master
分支上
$ git checkout master
然后合并 PR发送者/work
$ git merge PR发送者/work
先查看本地仓库和远程 GitHub端仓库库代码的差别
$ git diff origin/master
确认没有目的之外的差别后,进行push
$ git push
Counting objects: 10, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (10/10), 1.05 KiB | 0 bytes/s, done.
Total 10 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local object.
To github.com:SimpleLifee/nimon.git
8caf54d..067a3c8 master -> master
这样,仓库的 Pull Request
会自动从 Open
状态变为 Close
状态。
至此,Pull Request 的操作都介绍完了。
如果使用Homebrew
$ brew install hub
然后,在shell的环境路径后面添加 ~/bin
。
$ echo 'export PATH="~/bin:$PATH"' >> ~/.bash_profile
重新启动shell,就可以使用hub命令了。
$ hub --version
git version 2.11.0 (Apple Git-81)
hub version 2.2.9
使用hub命令的最佳实践是将相应的 git 设置成 hub 的别名。hub 命令可以完成 git 命令的所有操作,只需要在 shell 的配置文件中(.bash_profile) 添加下面一句即可。
eval "$(hub alias -s)"
hub 命令在初次访问 GitHub 的 API 的时候会询问用户名和密码。
$ cat ~/.config/hub
github.com:
- user: SimpleLifee
oauth_token: 5cb6fb57b65693dac153bf2c61dd642a916b268b
protocol: https
使用 hub clone
命令,可以省去指定 GitHub
端仓库的部分
$ hub clone nimon
上面这个命令与下面的命令效果相同。
$ git clone git@github.com/SimpleLifee/nimon.git
如果要指定用户,可以输入以下命令。
$ hub clone junoni/nimon
上面这个命令与下面的命令效果相同。
$ git clone git@github.com/junoni/nimon.git
$ hub remote add junoni
等同于
$ git remote add junoni git://github.com/junoni/nimon.git
类似于 hub remote add
hub cherry-pick
只需要输入 URL 就可以获取对应的修改并应用到当前分支。
$ hub cherry-pick https://github.com/SimpleLifee/SimpleLifee.github.io/commit/647c558f5b3767c2995dda5ddd5663d0466ed4dd
这个命令可以将下面两个命令的效果一次性执行
$ git remote add -f SimpleLifee git@github.com:SimpleLifee/SimpleLifee.github.io.git
$ git cherry-pick 647c558f5b3767c2995dda5ddd5663d0466ed4dd
hub fork
命令的功能与 GitHub 页面的 Fork 按钮相同,比如我们 clone 了其他用户的仓库,现在想 Fork 成自己的仓库,只需要执行
$ hub fork
这一命令,就可获得与下面这一系列操作相同的效果
(在 GitHub 对仓库做 Fork 处理)
$ git remote add -f 用户名 git@github.com:当前操作仓库的名字.git
执行完毕后,Fork 出的仓库会被设置成当前本地仓库的远程仓库(以用户名为标识符)