git基本命令学习

安装后初始化配置

配置全局的用户名(–global此电脑所有git仓库都会使用该配置)

$ git config --global user.name "Your Name"

配置全局的邮箱地址(–global此电脑所有git仓库都会使用该配置)

$ git config --global user.email "[email protected]"

查看配置信息

$ git config --system --list  ## 查看系统配置
$ git config --global  --list ## 查看当前用户配置
$ git config --local  --list  ## 查看当前仓库配置

创建版本库

创建一个空目录作为版本库目录

$ mkdir learngit # 创建目录learngit(即为版本库)
$ cd learngit    # 进入该目录
$ pwd            # 查看路径
/Users/michael/learngit

初始化该目录,使其可以被git管理,此后该目录会出现一个.git目录(如果没有可能被隐藏了,可以用:ls -ah查看)

$ git init  # 初始化该目录之后会出现以下提示
Initialized empty Git repository in /Users/michael/learngit/.git/
$ ls -ah # 查看当前目录文件,包括隐藏文件

在目录下面新建一个文件,用于做测试,内容随便

$ ls
readme.php
$ cat readme.php
Git is a version control system.
Git is free software.

将文件放入到仓库只需要两步
1. 告诉Git将要将要添加该文件到仓库(add后面可以跟多个文件用空格隔开,也可以跟目录,并且可以将文件多次分别add,只要在commit之前都算一次提交)

$ git add readme.txt
  1. 将文件提交到仓库
$ git commit -m "wrote a readme file" 
[master (root-commit) 74256b9] wrote a readme file
 2 files changed, 6 insertions(+)
 create mode 100644 reademe.php
 create mode 100644 readme.php

> ==注意:每次修改,如果不用git add到暂存区,那就不会加入到commit中==

对文件进行修改,添加一个单词,然后通过命令查看状态

$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

    modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

告诉我们文件被修改过了,但是还没有准备提交的修改

查看具体修改了哪些内容

$ git diff readme.php # 会显示出修改的内容信息

版本回退

查看所有的版本日志

$ git log # 如果需要精简到一行的信息加上参数 --pretty=oneline 即可
在Git中,用HEAD表示当前版本,也就是最新的提交1094adb...
(注意我的提交ID和你的肯定不一样),
上一个版本就是HEAD^,
上上一个版本就是HEAD^^,
当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

如下,回退到上一个版本,执行命令后用cat查看发现内容已经变了

$ git reset --hard HEAD^

如果我回到过去的版本了,随后又想恢复到原来的版本怎么办,只要命令框没有关闭,还可以找到原来的版本号,取前几位就可以,但是也不能太少,用以下命令

$  git reset --hard 3642b # 版本号写前几位就可以,但是也不能太短,能识别就行

但是如果手贱关闭了命令框,关闭了电脑,怎么办,回退版本后发现错了,还想回来怎么办

$ git reflog # 这个命令可以查看你所有操作命令的日志,当然里面是有版本号的了

工作区概念:就是你在本地电脑里能看到的目录

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

前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

>> 因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

撤销更改

情况一:准备提交之前如果发现了错误(==add之前==)
1. 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
2. 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
3. 总之,就是让这个文件回到最近一次git commit或git add时的状态。

$ git checkout -- readme.php

情况二:已经提交到暂存区了(==add之后commit之前==)
1. git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

$ git reset HEAD readme.php
  1. 此时就变为了情况一,暂存区没有了,但是工作区还有
$ git checkout -- readme.php

情况三:已经提交到了分支(==commit之后==)

可以采用版本回退的方法

情况四:不仅提交到了分支,还推送到了远程版本库

>> 那么恭喜你,本次撤销修改是不可能的了

删除文件

当你从本地删除了一个文件,可以有两种选择:
1. 确定要删除了,然后将分支中的文件也删除掉

$ git rm test.php
$ git commit -m "remove test.php"
  1. 发现删错了,想要将其从分支恢复回来
$ git checkout -- test.php

远程仓库操作

添加远程仓库
1. 第一步:==创建SSH Key==。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

$ ssh-keygen -t rsa -C "[email protected]"

注意:需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,密码没必要设置,如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对, ==id_rsa是私钥==,不能泄露出去,==id_rsa.pub是公钥==,可以放心地告诉任何人
2. 第二步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:
然后,点“==Add SSH Key==”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容

==为什么GitHub需要SSH Key呢?==

因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。

  1. ==在github上新建空的版本库==
$ git remote add origin git@github.com:KeepFang/learngit.git

注意:要将KeepFang换成自己的github用户名,learngit换成自己的远程库名字

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

  1. 将本地内容推送到远程库
$ git push -u origin master # 将本地库内容推送到远程库

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

从现在起,只要本地作了提交,就可以通过命令:

$ git push origin master

==SSH警告==

当你第一次使用Git的clone或者push命令连接GitHub时,会得到一个警告

The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。

Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了:

Warning: Permanently added 'github.com' (RSA) to the list of known hosts.

==克隆远程库文件到本地==

git clone git@github.com:用户名/版本库名.git

你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。

使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。

分支

分支在实际中怎么用呢?

团队合作开发一个项目,你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

  1. 创建分支
$ git checkout -b dev # 创建分支dev并切换到该分支

等价于

$ git branch dev # 创建分支
$ git checkout dev # 切换分支
$ git branch  # 列出所有分支,当前分支前面会标一个 * 号
  1. 合并分支
$ git checkout master  # 切换到主分支
$ git merge dev  # 将dev分支与当前分支合并
$ git branch -d dev # 合并完成之后就可以删除dev分支了
$ git branch  # 删除之后再次查看分支,发现只剩下master分支了

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

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

$ git merge --no-ff -m "merge with no-ff" dev # 禁用fast forward快速合并模式,
## 合并分支时,加上--no-ff参数就可以用普通模式合并,
## 合并后的历史有分支,能看出来曾经做过合并,
## 而fast forward合并就看不出来曾经做过合并。
$ git log --graph --pretty=oneline --abbrev-commit # 然后再查看分支历史


  1. 解决冲突

当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。

合并之后,删除没用的分支

$ git log --graph --pretty=oneline --abbrev-commit # graph参数是查看分支合并图

分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理:

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

bug分支

当你正在开发一个新功能的时候,突然有人反馈原先的项目存在一个bug,很自然想到新建一个分支来进行修复然后合并,但是现在你的工作还没完成,又不能提交,这时候就需要用到 ==保存现场== 功能

$ git stash # 将当前工作的现场储存起来
$ git status # 这时候再看发现工作区是干净的可以放心创建分支
  1. 确定在哪个分支修复bug,就从哪个分支创建临时分支,假设是master
$ git checkout master  # 切换到master分支
$ git checkout -b issue-101 # 创建并切换到bug分支
$ git add readme.txt 
$ git commit -m "fix bug 101" # 模拟修复bug
$ git checkout master # 切换到主分支
$ $ git merge --no-ff -m "merged bug fix 101" issue-101 # 将bug分支与主分支合并
  1. 修复bug后继续dev分支开发

$ git checkout dev # 继续返回dev写未完成的工作
$ git status # 此时工作区是干净的,那之前保存的现场在哪里呢
$ git stash list # 查看保存的工作现场

3.恢复之前的现场

$ git stash pop # 恢复现场并删除该stash
$ git stash list # 再次查看发现,已经没有stash了

等价于

$ git stash apply # 恢复现场
$ git stash drop  # 删除stash
$ git stash list # 再次查看发现,已经没有stash了

还可以多次stash,恢复指定现场

$ git stash apply stash@{0} # 恢复指定编号的现场

feature分支(新功能分支)

开发一个新功能,最好新建一个分支,至于怎么新建分支这个上面已经有概述

特殊情况:如果需要丢弃一个未合并的分支

$ git branch -D feature-vulcan # 如果要强制丢弃一个未合并的分支需要用大写的D参数

==多人协作==

  1. 查看远程仓库信息
$ git remote # 查看远程仓库信息
$ git remote -v # 查看远程仓库详细信息
  1. 推送分支到远程库
$ git push origin dev # 推送当前分支到指定的远程分支

但是,==并不是一定要把本地分支往远程推送==,那么,哪些分支需要推送,哪些不需要呢?

master分支是主分支,因此要时刻与远程同步;

dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;

bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;

feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!


  1. 抓取分支

  1. 模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@github.com:用户名/仓库名.git # 从服务器上拉取项目到本地
$ git branch # 拉取下来之后本地默认只能看到一个master分支
  1. 现在你的小伙伴要在dev分支上面进行开发了,于是他需要创建dev分支在本地
$ git checkout -b dev origin/dev # 创建=(远程)=的dev分支到本地
  1. 现在就可以开发dev分支,并时不时提交到远程
$ git add env.txt # 模拟开发dev分支
$ git commit -m "add env" 
$ git push origin dev # 提交分支到远程
  1. 如果多个人都在开发dev分支呢,为了保证一致性,需要先更新再提交
$ git add env.txt # 模拟你的提交
$ git commit -m "add new env" 
$ git push origin dev # 假设你的队友已经修改过dev分支了,那么会推送失败
$ git pull # 需要先pull更新代码为最新,可能还会报错,
## 因为没有建立本地dev与远程dev分支的直接链接
$ git branch --set-upstream-to=origin/dev dev # 按照报错信息建立链接
$ git pull # 这时候返回pull成功,但是可能你和队友修改了同样地方会提示有冲突
$ git commit -m "fix env conflict" # 解决冲突后,先提交,然后push
$ git push origin dev# 修复冲突后再次推送

rebase(变基:说白了就是美化分支线)

多人协作,分支很混乱,如果有强迫症非要整理成一条线呢

  1. 原来分支图是这样
$ git log --graph --pretty=oneline --abbrev-commit # 查看分支线
* 582d922 (HEAD -> master) add author
* 8875536 add comment
* d1be385 (origin/master) init hello
*   e5e69f1 Merge branch 'dev'
|\  
| *   57c53ab (origin/dev, dev) fix env conflict
| |\  
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
...

注意到Git用(HEAD -> master)和(origin/master)标识出当前分支的HEAD和远程origin的位置分别是582d922 add author和d1be385 init hello,本地分支比远程分支快两个提交。
2. 当我们再次提交,很不幸,有个人已经提前提交了,出现了冲突,按照习惯先pull一下

$ git push origin master # 假设失败了
$ git pull # 先pull一下
$ git status # 查看状态
$ git log --graph --pretty=oneline --abbrev-commit # 再次查看分支线,发现分叉了,
## 但是现在继续提交时完全没有问题的,就是线不好看
$ git rebase # 用命令美化线为一条
$ git log --graph --pretty=oneline --abbrev-commit # 再次查看分支线,发现变为了一条直线
$ git push origin master # 最后提交分支到远程

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

标签管理

tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。例如:v1.2

  1. 创建标签
$ git branch # 查看分支
$ git checkout master # 切换到分支
$ git tag v1.0 # 打标签
$ git tag # 查看所有标签

如果前面的忘记打标签现在要补上怎么办

$ git log --pretty=oneline --abbrev-commit # 找到对应版本号
$ git tag v0.9 f52c633 # 指定版本号打标签
$ git tag # 查看标签

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

$ git show v0.9 # 查看标签信息
$ git tag -a v0.1 -m "version 0.1 released" 1094adb # 要想带上标签说明,可以用-m参数
$ git show v0.1 # 这个命令同样可以查看到标签的说明信息


  1. 操作标签

删除本地标签

$ git tag -d v0.1

推送某个标签到远程

$ git push origin v1.0

一次性推送全部尚未推送到远程的本地标签

$ git push origin --tags

删除远程标签

$ git tag -d v0.9 # 先从本地删除
$ git push origin :refs/tags/v0.9 # 删除远程标签

Github上参与别人的开发

在GitHub上,可以任意Fork开源仓库;

自己拥有Fork后的仓库的读写权限;

可以推送pull request给官方仓库来贡献代码。

使用国内的码云(gitee)

  1. 先注册账号后配置公钥

  2. 如果已经有了一个本地仓库,想要关联到码云

    1. 首先在码云上面创建这个项目
    2. 将本地库只与码云库关联
$ git remote add origin git@gitee.com:用户名/项目名.git

==如果在使用命令git remote add时报错,说明本地已经关联了一个远程库==

此时先查看远程库信息

$ git remote -v

然后删除远程库信息,关联到gitee

$ git remote rm origin # 删除远程库
$ git remote add origin git@gitee.com:用户名/项目名.git # 关联码云库
$ git remote -v # 再次查看远程库信息


  1. 同时关联github和码云

使用多个远程库时,我们要注意,git给远程库起的默认名称是origin,如果有多个远程库,我们需要用不同的名称来标识不同的远程库。
1. 先删除已关联的名为origin的远程库

$ git remote rm origin
  1. 添加Github链接
$ git remote add github git@github.com:用户名/仓库名.git 
# 注意远程库叫github不叫origin了
  1. 添加码云链接
git remote add gitee git@gitee.com:用户名/仓库名.git
# 注意远程库叫gitee不叫origin了
$ git remote -v # 此时发现关联了github和gitee等多个远程库
  1. 然后就可以正常的pull和push了
## 更新代码为最新
git pull gitee master
git pull github master

## 推送到github远程库
$ git push github master
## 推送到gitee远程库
$ git push gitee master
## 如果不行就用
git push -u gitee master

忽略特殊文件(不能提交到远程库)

有些文件必须在项目目录,但是又不能提交他们,比如数据库密码配置文件

解决方法:在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件,详情参考廖雪峰git。

忽略文件的原则是:

  1. 忽略操作系统自动生成的文件,比如缩略图等;
  2. 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
  3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了

这个时候可以采用两种方法

  1. 一种是-f直接强制提交
$ git add -f App.class
  1. 一种是检查是不是过滤用的配置文件写错了
$ git check-ignore -v App.class

配置别名(给git命令添加别名)

配制方法:

$ git config --global alias.st status # 执行之后,就可以用st代替status
$ git config --global alias.unstage 'reset HEAD' # 用unstage代替reset HEAD

配置文件:配置好的规则实际上保存在本地的文件里面

配置Git的时候,加上–global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

每个仓库的Git配置文件都放在.git/config文件中,[alias]下面就是别名,可直接添加、修改或删除

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = git@github.com:michaelliao/learngit.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[alias]
    last = log -1

你可能感兴趣的:(协同开发与工具软件,git,github)