4

走在前端的大路上

最后更新日期2018年12月28日(第四节)


Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

git与github有什么区别?

git(工具)是一个版本控制工具

github(社区)是一个用git做版本控制的项目托管平台,并附带交友分享功能。。类似的平台还有bitbucket、oschina的码云这里写图片描述(逗逼名字)。 这些平台基本都是以开源项目著称的,当然也提供一定的收费私有化托管服务。 当然(私有化),估计大家还听说过coding、gitlab、gogs,这些都是做一些私有化项目托管的平台。gitlab、gogs都是开源的git托管平台,可以自己私有化部署。

git和svn的区别

svn是一个中心化的版本控制工具
git是一个去中心化的分布式版本控制工具

一. 注册GitHub帐号

1. 注册帐号

使用github首先得 注册个账号,具体的流程就不演示了

clipboard.png

2. 查看资料

注册成功之后Sign in(登录)进去,点击Your profile菜单到你自己的用户资料页去看看都有什么内容:

clipboard.png

3. 新建仓库

点击New Repository菜单,进入创建仓库界面,下面的内容请看仔细:

clipboard.png

clipboard.png

4. 进入仓库

创建完成之后,进入项目主页,就像这样,只有一个README.md文件:

clipboard.png

5. 克隆项目到本地

下一步,把这个项目克隆到你本地去,在项目主页上点这里:

clipboard.png

Windows用户

在你的电脑里面任意选择一个目录,在任意空白处右键,选择”Git clone”:

clipboard.png

看到Success说明克隆成功,这样仓库的内容就到你本地了:

clipboard.png


二. Github 创建公钥 SSH key

1.关于SSH

SSH协议,可以连接和验证远程服务器和服务。使用SSH密钥,可以连接到GitHub,而无需在每次访问时提供用户名或密码。

2.create SSH key:

1.在终端内执行:

cd ~/.ssh

如果返回No such file or directory那就说明没有生成过SSH key,直接进入第3步

2.如果没有出现上面的情况说明你之前已经生成过SSH key, 输入ls -al ~/.ssh查看现有的密钥是否存在

默认情况下,公钥的文件名是id_rsa.pub,看看你自己是否有。

3.生成新的SSH key:(邮箱替换成自己 github 注册邮箱)

ssh-keygen  -t   rsa   -C  "76....@qq.com"

之后会要求确认路径和输入密码,我是一路回车默认

成功的话会在 ~/ 下生成 .ssh文件夹,进去,打开 id_rsa.pub,复制里面的key。

 cd ~/.ssh
ls
//id_rsa id_rsa.pub
cat id_rsa.pub
//ssh-rsa *******好长一段********** 76.....@qq.com

clipboard.png

3.Add SSH key

1.登陆到你的Github,进入settings

clipboard.png

clipboard.png

clipboard.png

title:可以顺便填名字
key:在Key文本框里粘贴id_rsa.pub文件的内容
点击add key 配置完成

2.测试是否配置成功

ssh -T git@github.com

配置成功标志

Hi xxxxxx!You've successfully authenticated,but Gitub does not provide shell access.

回到github,刷新网页就可以看到钥匙旁的灰色小圆点变绿,就表明已经添加成功了。(如果网速慢,可能要稍等一会)

clipboard.png

三. 使用git在本地建立的项目更新到Github

1.Git 设置提交代码时的用户信息:

git config --global user.name "yumengzhong"
git config --global user.email "76...@qq.com"

创建 git 仓库:

mkdir test    // 首先在本地新建文件夹
cd test       // 进入这个文件夹
git init     // 在当前目录初始化一个git仓库
//git init [project-name]   新建一个目录,将其初始化为Git代码库
touch README.md
git add README.md
git commit -m "first commit"
git remote add origin https://..../test.git    //将git本地仓库和Github远程仓库关联
git push -u origin master

已有项目?

cd exist_git_demo
git remote add origin https://..../test.git
git push -u origin master

其中origin代表的是你远程的仓库

1.修改仓库名
一般来讲,默认情况下,在执行clone或者其他操作时,仓库名都是 origin 如果说我们想给他改改名字,比如我不喜欢origin这个名字,想改为 oschina 那么就要在仓库目录下执行命令:

git remote rename origin oschina

这样 你的远程仓库名字就改成了oschina,同样,以后推送时执行的命令就不再是 git push origin master 而是 git push oschina master 拉取也是一样的

2.添加一个仓库
在不执行克隆操作时,如果想将一个远程仓库添加到本地的仓库中,可以执行

git remote add origin  仓库地址

注意: 1.origin是你的仓库的别名 可以随便改,但请务必不要与已有的仓库别名冲突 2. 仓库地址一般来讲支持 http/https/ssh/git协议,其他协议地址请勿添加

3.查看当前仓库对应的远程仓库地址

git remote -v

这条命令能显示你当前仓库中已经添加了的仓库名和对应的仓库地址,通常来讲,会有两条一模一样的记录,分别是fetch和push,其中fetch是用来从远程同步 push是用来推送到远程

clipboard.png

4.修改仓库对应的远程仓库地址

git remote set-url origin 仓库地址

如果已经配置好ssh公钥,可以使用ssh地址(即:git@。。。.git),如果您没有配置公钥,请使用https地址

小例子:

clipboard.png

由于之前没有配置用户名,所以首次commit会有提示,自动建立

$ git config --global user.name Your Name
$ git config --global user.email email@example.com

公有库开发过程

  • fork仓库

    • 通常fork公有库的Master分支作为当前的开发分支
  • 提交pr
  • pr审核
  • pr合并

fork仓库 | 提交pr | pr审核 | pr合并

克隆仓库 git clone https://.....git
切换到dev分支 git checkout dev
创建分支 git checkout -b [new-feature]
提交分支 git push origin [new-feature]
本地分支合并 查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>

四. 常规操作

本节整理自 廖雪峰-Git教程

4.1 基础知识

4.1.1工作区(Working Directory)

就是你在电脑里能看到的目录就是一个工作区:

4.1.2版本库(Repository)

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

把文件往Git版本库里添加的时候,是分两步执行的:

  • 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
  • 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

4.1.3

  • git diff HEAD -- readme.txt命令可以查看工作区和版本库里面最新版本的区别
  • git log命令显示从最近到最远的提交日志,如果嫌输出信息太多,可以用git log --pretty=oneline

    // 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
    // e475afc93c209a690c39c13a46716e8fa000c366 add distributed
    // eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file

4.1.4 查看远程库的信息

$ git remote
origin

```
$ git remote -v
origin  git@github.com:michaelliao/learngit.git (fetch)
origin  git@github.com:michaelliao/learngit.git (push)
```
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。


删除已有的GitHub远程库`git remote rm origin`

添加远程库(注意路径中需要填写正确的用户名)`git remote add origin git@gitee.com:liaoxuefeng/learngit.git`

4.2 撤销操作

4.2.1撤销“本地修改未git add”的文件

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:

  • 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
  • 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近一次git commit或git add时的状态。

4.2.2 撤销“修改并git add”的文件

用命令git reset HEAD <file>可以把暂存区的修改撤销掉(unstage),重新放回工作区,然后回到 4.3.1

4.2.3 撤销“修改并git commit提交”的文件

首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD
表示当前版本,也就是最新的提交1094adb...(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

git reset --hard HEAD^
// 或
$ git reset --hard eaadf4e385e865d25c48e...

git reflog用来记录你的每一次命令:

总结一下:

  • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id
  • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
  • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

4.3 删除操作

一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了:

$ rm test.txt

这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了

现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit:

$ git rm test.txt
// 小提示:先手动删除文件,然后使用git rm <file>和git add<file>效果是一样的。

$ git commit -m "remove test.txt"

另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

$ git checkout -- test.txt

git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。

4.4 添加远程库

要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git

关联后,使用命令git push -u origin master第一次推送master分支的所有内容;

此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;

4.5 从远程库克隆

$ git clone git@github.com:michaelliao/gitskills.git

4.6 创建与合并分支

Git鼓励大量使用分支:

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>

创建+切换分支:git checkout -b <name>

合并某分支到当前分支:git merge <name>

删除分支:git branch -d <name>

查看分支合并图:git log --graph。

合并dev分支,请注意--no-ff参数,表示禁用Fast forward:

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

git merge --no-ff -m "merge with no-ff" dev
//因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

4.7 Bug分支

场景:突然需要修复一个bug,但是正在 dev上进行的工作还没提交,,并且进行了一半还不能提交
Git提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作

$ git stash
Saved working directory and index state WIP on dev: f52c633 add merge

现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。

然后确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
  (use "git push" to publish your local commits)

$ git checkout -b issue-101
Switched to a new branch 'issue-101'

修复完成后提交,切回master分支,并完成合并,最后删除issue-101分支

$ git add readme.txt 
$ git commit -m "fix bug 101"
$ git checkout master
$ git merge --no-ff -m "merged bug fix 101" issue-101
$ git branch -d issue-101

bug修复完,是时候接着回到dev分支干活了!

$ git checkout dev
Switched to branch 'dev'

$ git status
On branch dev
nothing to commit, working tree clean

工作区是干净的,刚才的工作现场存到哪去了?
git stash list命令看看:

$ git stash list
stash@{0}: WIP on dev: f52c633 add merge

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

  • 一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
  • 另一种方式是用git stash pop,恢复的同时把stash内容也删了:

4.8 删除分支

$ git branch -d feature-vulcan
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.

销毁失败。Git友情提醒,feature-vulcan分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用大写的-D参数。。

现在我们强行删除:

$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 287773e).

4.9 多人协作

当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。

现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:

$ git checkout -b dev origin/dev

你的小伙伴做了修改,并

$ git add env.txt

$ git commit -m "add env"

$ git push origin dev

而碰巧你也对同样的文件作了修改,并试图推送

$ git add env.txt

$ git commit -m "add new env"
[dev 7bd91f1] add new env
 1 file changed, 1 insertion(+)
 create mode 100644 env.txt

$ git push origin dev
To github.com:michaelliao/learngit.git
 ! [rejected]        dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:

$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> dev

git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:

$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

再pull:

$ git pull
Auto-merging env.txt
CONFLICT (add/add): Merge conflict in env.txt
Automatic merge failed; fix conflicts and then commit the result.

这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:

$ git commit -m "fix env conflict"

$ git push origin dev

因此,多人协作的工作模式通常是这样:

  • 首先,可以试图用git push origin <branch-name>推送自己的修改;
  • 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  • 如果合并有冲突,则解决冲突,并在本地提交;
  • 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

这就是多人协作的工作模式,一旦熟悉了,就非常简单。

小结

  • 查看远程库信息,使用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,如果有冲突,要先处理冲突。

rebase操作可以把本地未push的分叉提交历史整理成直线;

rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比

4.10 标签管理

4.10.1创建标签

在需要打标签的分支上,git tag <name>就可以打一个新标签

$ git tag v1.0

可以用命令git tag查看所有标签:

$ git tag
v1.0

默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?

方法是找到历史提交的commit id,然后打上就可以了:

$ git log --pretty=oneline --abbrev-commit
12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
5dc6824 & simple

比方说要对add merge这次提交打标签,它对应的commit idf52c633,敲入命令:

$ git tag v0.9 f52c633

再用命令git tag查看标签:

$ git tag
v0.9
v1.0

注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>查看标签信息:

$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 21:56:54 2018 +0800

    add merge

diff --git a/readme.txt b/readme.txt
...

可以看到,v0.9确实打在add merge这次提交上。

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字

$ git tag -a v0.1 -m "version 0.1 released" 1094adb

用命令git show <tagname>可以看到说明文字:

$ git show v0.1
tag v0.1
Tagger: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 22:48:43 2018 +0800

version 0.1 released

commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (tag: v0.1)
Author: Michael Liao <askxuefeng@gmail.com>
Date:   Fri May 18 21:06:15 2018 +0800

    append GPL

diff --git a/readme.txt b/readme.txt
...

注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。

小结

  • 命令git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id
  • 命令git tag -a <tagname> -m "blablabla..."可以指定标签信息;
  • 命令git tag可以查看所有标签。

4.10.2操作标签

如果标签打错了,也可以删除 git tag -d v0.1
如果要推送某个标签到远程,使用命令git push origin <tagname>
一次性推送全部尚未推送到远程的本地标签git push origin --tags
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除git tag -d v0.9,然后,从远程删除。删除命令也是push,但是格式如下git push origin :refs/tags/v0.9,要看看是否真的从远程库删除了标签,可以登陆GitHub查看

4.11 其他

4.11.1一个本地库既关联GitHub,又关联码云

使用多个远程库时,我们要注意,git给远程库起的默认名称是origin,如果有多个远程库,我们需要用不同的名称来标识不同的远程库。

1.先删除已关联的名为origin的远程库git remote rm origin

2.然后,先关联GitHub的远程库git remote add github git@github.com:michaelliao/learngit.git
注意,远程库的名称叫github,不叫origin了。

3.接着,再关联码云的远程库git remote add gitee git@gitee.com:liaoxuefeng/learngit.git
同样注意,远程库的名称叫gitee,不叫origin

4.现在,我们用git remote -v查看远程库信息,可以看到两个远程库:

git remote -v
gitee    git@gitee.com:liaoxuefeng/learngit.git (fetch)
gitee    git@gitee.com:liaoxuefeng/learngit.git (push)
github    git@github.com:michaelliao/learngit.git (fetch)
github    git@github.com:michaelliao/learngit.git (push)

5.
如果要推送到GitHub,使用命令git push github master
如果要推送到码云,使用命令git push gitee master

4.11.2.gitignore文件

4.11.3 配置别名

$ git config --global alias.st status
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
$ git config --global alias.unstage 'reset HEAD'
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"

4.12 Git服务器

4.13 使用git stash命令保存和恢复进度

场景:我们有时会遇到这样的情况,正在dev分支开发新功能,做到一半时有人过来反馈一个bug,让马上解决,但是新功能做到了一半你又不想提交,这时就可以使用git stash命令先把当前进度保存起来,然后切换到另一个分支去修改bug,修改完提交后,再切回dev分支,使用git stash pop来恢复之前的进度继续开发新功能。

git stash
保存当前工作进度,会把暂存区和工作区的改动保存起来。执行完这个命令后,在运行git status命令,就会发现当前是一个干净的工作区,没有任何改动。使用git stash save 'message...'可以添加一些注释

git stash list
显示保存进度的列表

git stash clear
删除所有存储的进度。

git stash pop [–index] [stash_id]

  • git stash pop 恢复最新的进度到工作区。git默认会把工作区和暂存区的改动都恢复到工作区。
  • git stash pop --index 恢复最新的进度到工作区和暂存区。(尝试将原来暂存区的改动还恢复到暂存区)
  • git stash pop stash@{1}恢复指定的进度到工作区。stash_id是通过git stash list命令得到的

通过git stash pop命令恢复进度后,会删除当前进度。

git stash apply [–index] [stash_id]
除了不删除恢复的进度之外,其余和git stash pop 命令一样。

git stash drop [stash_id]
删除一个存储的进度。如果不指定stash_id,则默认删除最新的存储进度。


问题总结

1.disconnected no supported authentication methods available(server sent: publickey)

描述1: 安装好小乌龟Git后,用小乌龟的pull 从github上拉取项目,遇到错误:
disconnected no supported authentication methods available(server sent: publickey)
或者是 git did not exit cleanly (exit code 1)
亦或者是 git did not exit cleanly (exit code 128)

多半是因为git和小乌龟有冲突,解决方法:
右键--小乌龟---settings--network--修改ssh client为 git 的 ssh.exe

clipboard.png

点击 browse按钮打开文件目录,找到git目录下的ssh.exe,确认即可。

clipboard.png

替换成功,后,再pull一下。应该就能正常的pull成功。如果不行,再把SSH client`改回小乌龟自己的程序,再试一下。

2.在向刚创建的github版本库 push代码时出错:

clipboard.png

网上有说,是因为远程repository和我本地的repository冲突导致的,而我在创建版本库后,在github的版本库页面点击了创建README.md文件的按钮创建了说明文档,但是却没有pull到本地。这样就产生了版本冲突的问题。

然后 执行 git pull

$ git pull
warning: no common commits
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 12 (delta 1), reused 8 (delta 0), pack-reused 0
Unpacking objects: 100% (12/12), done.
From github.com:yumengzhong/gittext
 * [new branch]      master     -> origin/master
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
 
    git pull <remote> <branch>
 
If you wish to set tracking information for this branch you can do so with:
 
    git branch --set-upstream-to=origin/<branch> master

根据返回的提示查询, 这个问题应该是 Git新建本地分支与远程分支关联问题:git branch --set-upstream

解析:
Git在本地新建分支后,必须要做远程分支关联。关联目的是如果在本地分支下进行git pull 和 git push操作时 ,不需要指定在命令行指定远程的分支. 推送到远程分支时,没有关联的情况下而且没有指定, git pull 的时候,就会提示你如下信息:

解决方法:

实例如下,其中feature为创建的分支

//“--set-upstream”选项已被直接替换为“--track”

git branch --track feature origin/feature

//另外还有一个新的语法

git branch --set-upstream-to=origin/feature feature

命令的最终修改都是针对 config 文件。

但是 现在执行 git pull 仍不行

$ git pull
//fatal: refusing to merge unrelated histories
//大致意思就是无法将两个没有共同祖先的两个仓库合并

解决方法:

git pull origin master --allow-unrelated-histories

推荐阅读:
1.?Git 常用操作总结
2.从只会git add .的菜鸟到掌握git基本功能

参考文章:
1.大漠穷秋-注册github账号并创建项目
2.http://blog.csdn.net...
3.如何使用git实现团队协作开发
4.廖雪峰-git教程
5.阮一峰-常用 Git 命令清单
6.廖雪峰-多人协作
7.Git 常用命令与名词解释
8.Git 仓库的基本操作

附录一:Git 常用命令与名词解释

clipboard.png
注:图片来源(阮一峰-常用 Git 命令清单

  • Workspace:工作区
  • Index / Stage:暂存区
  • Repository:仓库区(或本地仓库)
  • Remote:远程仓库

仓库
在 Git 的概念中,仓库,就是你存在.git目录的那个文件夹内的所有文件,包括隐藏的文件,Git程序会在当前目录以及上级目录查找是否存在.git文件,如果存在,则会将.git目录存在的文件夹开始下的所有文件当成你需要管理的文件,所以,我们如果想将某个文件夹当做一个Git仓库,你可以在那个文件夹下通过终端(Window为Cmd或者PoewrShell或者Bash)来执行

git init
这样,你所期望的那个文件夹就成为了一个Git管理的仓库了

版本
严格来讲,Git并不存在版本的概念,但人们也硬是发展出了这么个玩意,在Git中,计数基础是提交,即我们常说的Commit,我们每做一点更改便可以产生一次提交,当提交累计起来,可以作为产品定型时,就在当前的Commit上打上一个标记,将这个标记我们称之为版本多少多少,那么就算完成了一个版本,标记本身被称之为Tag,请注意,在Git中,版本仅仅只是某一个提交的标签,并没有其他意义,Git本身也仅有打标签的功能,并没有版本功能,版本功能是根据Tag来扩展的,Git本身并没有

分支
这是Git中最重要的也是最常用的概念和功能之一,分支功能解决了正在开发的版本与上线版本稳定性冲突的问题在Git使用过程中,我们的默认分支一般是Master,当然,这是可以修改的,我们在Master完成一次开发,生成了一个稳定版本,那么当我们需要添加新功能或者做修改时,只需要新建一个分支,然后在该分支上开发,完成后合并到主分支即可

提交
提交在Git中同样是非常重要的概念,Git对于版本的管理其实是对于提交的管理,在整个Git仓库中,代码存在的形式并不是一分一分的代码,而是一个一个的提交,Git使用四十个字节长度的16进制字符串来标识每一个提交,这基本保证了每一个提交的标识是唯一的,然后通过组织一个按照时间排序的提交列表,就组成了我们所说的分支,请注意,分支在本质上只是一个索引,所以,我们可以任意回退,修正,即使因为某些原因丢失了,也可以重建另外,关于Git的储存方式:Git是仅仅只储存有修改的部分,并不会储存整个文件,所以,请不要删除文件夹整个文件夹的内容,除非你确定你不再需要他,否则请勿删除

同步
同步,也可以称之为拉取,在Git中是非常频繁的操作,和SVN不同,Git的所有仓库之间是平等的,所以,为了保证代码一致性,尽可能的在每次操作前进行一次同步操作,具体的为在工作目录下执行如下命令:

git pull origin master
其中origin代表的是你远程的仓库,可以通过命令 git remote -v 查看,master是分支名,如果你本地是其他分支,请换成其他分支的名字,另,因为远程仓库与你本地仓库可能存在冲突,故当存在冲突时,请参考进阶篇的如何处理冲突

推送
和拉取一样,也是一个非常频繁的操作,当你代码有更新时,你需要更新到远程仓库,这个动作被称之为推送,执行的命令与拉取一样,只是将其中的pull这个单词改成push,同样,如果远程仓库存在你本地仓库没有的更新,则在推送前你需要先进行一次同步,如果你确定你不需要远程的更新,则在推送时加上 -f 选项,则可以强制推送,注:在协同开发中,我并不建议这么做,因为这样很可能覆盖别人的代码

推送代码示例:

git push origin master

强制推送代码示例:

git push origin master -f

冲突
在使用Git开发时,如果只是一个人使用,那么基本不会产生冲突,但是在多人合作开发的情况下,产生冲突是很正常的一件事情,关于如何处理冲突,请参考进阶篇的如何处理代码冲突 这一小节

合并
合并这个命令通常情况下是用于两个分支的合并,一般用于本地分支,远程分支多用Pull命令,该命令的功能是将待合并分支与目标分支合并在一起,注意,这个命令只会合并当前版本之前的差异,两个分支的提交历史会根据提交时间重新组织索引,故只可能会产生一次冲突但是会生成一个提交,如果你不想生成这次提交,加上 --base参数即可

暂存
这个既是一个概念也是一个命令,其含义就是字面上的,作用就是可以将你当前正在进行的工作暂时存起来,然后在此基础上干别的事情,等你别的事情干完后,再转回来继续,注意,暂存只是针对你最后一次改动而言,即针对当前所在的版本的所有改动都算具体执行命令为:

将当前改动暂存起来:

git stash

恢复最后一次暂存的改动

git stash pop

查看有多少暂存`

git stash list

撤销
撤销命令使用是非常频繁的,因为某些原因,我们不再需要我们的改动或者新的改动有点问题,我们需要回退到某个版本,这时就需要用到撤销命令,或者说这个应该翻译成重置更加恰当。具体命令如下:

撤销当前的修改:

git reset --hard

请注意:以上命令会完全重置你的修改,如果你想保留某些文件,请使用checkout +文件路径 命令来逐一撤销修改

如果你想重置到某一版本,可以将 --hard 改为具体的Commit的id如:

git reset 1d7f5d89346

请注意,这时你的修改仍然存在,只是你的最近一次提交的版本号变成了你要重置的版本,如果说你想完全丢弃修改,只需要加上 --hard参数就可以

附录二:常用 Git 命令清单

1、增加/删除文件

# 添加指定文件到暂存区
$ git add [file1] [file2] ...

# 添加指定目录到暂存区,包括子目录
$ git add [dir]

# 添加当前目录的所有文件到暂存区
$ git add .

# 添加每个变化前,都会要求确认
# 对于同一个文件的多处变化,可以实现分次提交
$ git add -p

# 删除工作区文件,并且将这次删除放入暂存区
$ git rm [file1] [file2] ...

# 停止追踪指定文件,但该文件会保留在工作区
$ git rm --cached [file]

# 改名文件,并且将这个改名放入暂存区
$ git mv [file-original] [file-renamed]

2、代码提交

# 提交暂存区到仓库区
$ git commit -m [message]

# 提交暂存区的指定文件到仓库区
$ git commit [file1] [file2] ... -m [message]

# 提交工作区自上次commit之后的变化,直接到仓库区
$ git commit -a

# 提交时显示所有diff信息
$ git commit -v

# 使用一次新的commit,替代上一次提交
# 如果代码没有任何新变化,则用来改写上一次commit的提交信息
$ git commit --amend -m [message]

# 重做上一次commit,并包括指定文件的新变化
$ git commit --amend [file1] [file2] ...

3、分支

# 列出所有本地分支(*代表当前所在分支)
$ git branch

# 列出所有远程分支
$ git branch -r

# 列出所有本地分支和远程分支
$ git branch -a

# 新建一个分支,但依然停留在当前分支
$ git branch [branch-name]

# 新建一个分支,并切换到该分支
$ git checkout -b [branch]

# 新建一个分支,指向指定commit
$ git branch [branch] [commit]

# 新建一个分支,与指定的远程分支建立追踪关系
$ git branch --track [branch] [remote-branch]

# 切换到指定分支,并更新工作区
$ git checkout [branch-name]

# 切换到上一个分支
$ git checkout -

# 建立追踪关系,在现有分支与指定的远程分支之间
$ git branch --set-upstream [branch] [remote-branch]

# 合并指定分支到当前分支
$ git merge [branch]

# 选择一个commit,合并进当前分支
$ git cherry-pick [commit]

# 删除分支
$ git branch -d [branch-name]

# 删除远程分支
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]

4、标签

# 列出所有tag
$ git tag

# 新建一个tag在当前commit
$ git tag [tag]

# 新建一个tag在指定commit
$ git tag [tag] [commit]

# 删除本地tag
$ git tag -d [tag]

# 删除远程tag
$ git push origin :refs/tags/[tagName]

# 查看tag信息
$ git show [tag]

# 提交指定tag
$ git push [remote] [tag]

# 提交所有tag
$ git push [remote] --tags

# 新建一个分支,指向某个tag
$ git checkout -b [branch] [tag]

5、查看信息

# 显示有变更的文件
$ git status

# 显示当前分支的版本历史
$ git log

# 显示commit历史,以及每次commit发生变更的文件
$ git log --stat

# 搜索提交历史,根据关键词
$ git log -S [keyword]

# 显示某个commit之后的所有变动,每个commit占据一行
$ git log [tag] HEAD --pretty=format:%s

# 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件
$ git log [tag] HEAD --grep feature

# 显示某个文件的版本历史,包括文件改名
$ git log --follow [file]
$ git whatchanged [file]

# 显示指定文件相关的每一次diff
$ git log -p [file]

# 显示过去5次提交
$ git log -5 --pretty --oneline

# 显示所有提交过的用户,按提交次数排序
$ git shortlog -sn

# 显示指定文件是什么人在什么时间修改过
$ git blame [file]

# 显示暂存区和工作区的差异
$ git diff

# 显示暂存区和上一个commit的差异
$ git diff --cached [file]

# 显示工作区与当前分支最新commit之间的差异
$ git diff HEAD

# 显示两次提交之间的差异
$ git diff [first-branch]...[second-branch]

# 显示今天你写了多少行代码
$ git diff --shortstat "@{0 day ago}"

# 显示某次提交的元数据和内容变化
$ git show [commit]

# 显示某次提交发生变化的文件
$ git show --name-only [commit]

# 显示某次提交时,某个文件的内容
$ git show [commit]:[filename]

# 显示当前分支的最近几次提交
$ git reflog

6、远程同步

# 下载远程仓库的所有变动
$ git fetch [remote]

# 显示所有远程仓库
$ git remote -v

# 显示某个远程仓库的信息
$ git remote show [remote]

# 增加一个新的远程仓库,并命名
$ git remote add [shortname] [url]

# 取回远程仓库的变化,并与本地分支合并
$ git pull [remote] [branch]

# 上传本地指定分支到远程仓库
$ git push [remote] [branch]

# 强行推送当前分支到远程仓库,即使有冲突
$ git push [remote] --force

# 推送所有分支到远程仓库
$ git push [remote] --all

7、撤销

# 恢复暂存区的指定文件到工作区
$ git checkout [file]

# 恢复某个commit的指定文件到暂存区和工作区
$ git checkout [commit] [file]

# 恢复暂存区的所有文件到工作区
$ git checkout .

# 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变
$ git reset [file]

# 重置暂存区与工作区,与上一次commit保持一致
$ git reset --hard

# 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变
$ git reset [commit]

# 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致
$ git reset --hard [commit]

# 重置当前HEAD为指定commit,但保持暂存区和工作区不变
$ git reset --keep [commit]

# 新建一个commit,用来撤销指定commit
# 后者的所有变化都将被前者抵消,并且应用到当前分支
$ git revert [commit]

# 暂时将未提交的变化移除,稍后再移入
$ git stash
$ git stash pop

于梦中2010
2.1k 声望181 粉丝

前端菜鸟儿,请多关照!