文章目录
本地git客户端生成ssh-key
ssh-keygen -t rsa -C ‘xxx@xxx.com’
其中xxx@xxx.com即为你的邮箱地址,点击回车,会让你选择存储路径,此时不用理会直接回车,其会保存到默认路径
基本的 Git 工作流程
- 在工作目录中修改文件
- 暂存文件,将文件的快照放入暂存区域
- 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录
git help帮助命令
'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
命令 | 含义 |
---|---|
git help | |
git help --all或-a | 显示所有命令 |
git help --guide或-g | 查看用户手册 |
git help | 查看某个命令手册 |
git config用户配置命令
命令 | 含义 |
---|---|
git config --system | 系统范围内配置 |
git config --golbal | 用户全局配置,~/.gitconfig 隐藏文件中 |
git config --local | 使用 repository的配置 |
git config --list或-l | 列出配置项信息 |
git config --unset user.name name | 取消设置的name用户名 |
git config --replace-all user.name newname | 重新配置 |
初次运行 Git 前的配置
一般在新的系统上,我们都需要先配置下自己的 Git 工作环境。配置工作只需一次,以后升级时还会沿用现在的配置。当然,如果需要,你随时可以用相同的命令修改已有的配置。
Git 提供了一个叫做 git config 的工具(译注:实际是 git-config 命令,只不过可以通过 git 加一个名字来呼叫此命令。),专门用来配置或读取相应的工作环境变量。而正是由这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:
/etc/gitconfig 文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
~/.gitconfig 文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。
在 Windows 系统上,Git 会找寻用户主目录下的 .gitconfig 文件。主目录即 $HOME 变量指定的目录,一般都是 C:\Documents and Settings$USER。此外,Git 还会尝试找寻 /etc/gitconfig 文件,只不过看当初 Git 装在什么目录,就以此作为根目录来定位。
用户信息
第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录:
$ git config --global user.name “John Doe”
$ git config --global user.email johndoe@example.com
如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。
文本编辑器
接下来要设置的是默认使用的文本编辑器。Git 需要你输入一些额外消息的时候,会自动调用一个外部文本编辑器给你用。默认会使用操作系统指定的默认编辑器,一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置:
$ git config --global core.editor emacs
差异分析工具
还有一个比较常用的是,在解决合并冲突时使用哪种差异分析工具。比如要改用 vimdiff 的话:
$ git config --global merge.tool vimdiff
Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的输出信息。当然,你也可以指定使用自己开发的工具,具体怎么做可以参阅第七章。
查看配置信息
要检查已有的配置信息,可以使用 git config --list 命令:
$ git config --list
user.name=Scott Chacon
user.email=schacon@gmail.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
…
有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig 和 ~/.gitconfig),不过最终 Git 实际采用的是最后一个。
git init 初始化项目
命令 | 含义 |
---|---|
git init | 生成一个隐藏的.git文件夹 |
git status 显示当前分支状态
当当前分支发生修改是,执行此命令会显示没有跟踪的文件:
Git 有三种状态,你的文件可能处于其中之一:
- 已提交(committed):已提交表示数据已经安全的保存在本地数据库中
- 已修改(modified):已修改表示修改了文件,但还没保存到数据库中
- 已暂存(staged):已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中
git log 显示提交日志信息
命令 | 含义 |
---|---|
git log | 显示日志详细信息 |
git log --oneline | 一行显示每次提交信息 |
git log -n | n表示最近的n个提交信息 |
git log --graph | 显示ASCII图形表示的分支合并历史 |
git log --author=A | 作者为A的提交历史 |
实战1:本地创建项目版本控制步骤
1. git init //项目文件夹下执行
Initialized empty Git repository in E:/data/Qt5/
2. git status //执行此命令,查看状态
Untracked files:
(use "git add <file>..." to include in what will be committed)
3. git add .(.表示当前所有文件)或指定文件名 //修改提交到暂存区
4. git status //继续执行此命令
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
5. git commit -m '提交说明' //暂存区向git本地库提交
6. git status //此时显示工作空间干净
On branch master
nothing to commit, working directory clean
git branch 分支操作
创建git仓库时,默认是创建生成一个主分支,即On branch master,当你需要自己开发一个新模块,要从开发主线上分离开来,可以创建一个新的分之,以免影响开发主线。
命令 | 含义 |
---|---|
git branch 不接参数或–list(-l) | -l为–list简写 查看当前分支,(*)后为当前分支 |
git branch dev | 创建新分支dev |
git branch -a | 查看当前本地和远程分支 |
git branch -r | 查看在远程分支 |
git branch -m name newname | 修改分支名 |
git branch --delete(-d) name | -d为–delete简写删除分支 |
git tag 打标签
命令 | 含义 |
---|---|
git tag | 查看所有标签 |
git tag | 给当前分支打tag,命名为tagname |
git tag | 给commitid提交设置新的tag,命名为tagname |
git clone --branch [tags标签] [git地址] | 获取指定的tag分支 |
git merge 和git rebase分支合并
命令 | 含义 |
---|---|
git merge dev | 将dev分支合并到当前分支,当前分支和合并到的分支会形成环路 |
git rebase dev | 将dev分支合并到当前分支,当前分支的前面提(commit)会被取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把"mywork"分支更新为最新的"dev"分支,最后把保存的这些补丁应用到"mywork"分支上 |
git reset 重置
如果想恢复到之前某个提交的版本,且那个版本之后提交的版本我们都不要了,就可以用这种方法
命令 | 含义 |
---|---|
git reset --soft | 软重置,不会影响工作区和暂存区后接ID号 |
git reset --hard | 直接重置工作区和暂存区 |
git reset --mixed | 默认只重置暂存区 |
git reset –-soft:回退到某个版本,只回退了commit的信息,不会恢复到暂存区一级。如果还要提交,直接commit即可;
git reset -–hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,撤销的commit中所包含的更改被冲掉;
在rebase的过程中,也许会出现冲突(conflict). 在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用"git-add"命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行:$ git rebase --continue
,这样git会继续应用(apply)余下的补丁。
在任何时候,你可以用–abort参数来终止rebase的行动,并且"mywork" 分支会回到rebase开始前的状态。$ git rebase --abort
git diff指令
1.git diff
1.1 当工作区有改动,暂存区为空,diff的对比是“工作区与最后一次commit提交的仓库的共同文件”;
1.2 当工作区有改动,暂存区不为空,diff对比的是“工作区与暂存区的共同文件”。
2.git diff --cached 或 git diff --staged
显示暂存区(已add但未commit文件)和最后一次commit(HEAD)之间的所有不相同文件的增删改(git diff --cached和git diff –staged相同作用)
3.git diff HEAD
显示工作目录(已track但未add文件)和暂存区与最后一次commit之间的的所有不相同文件的增删改。
3.1 git diff HEAD~X或git diff HEAD^^^…(后面有X个^符号):可以查看最近一次提交的版本与往过去时间线前数X个的版本之间的所有同3中定义文件之间的增删改。
4.git diff <分支名1> <分支名2> :
比较两个分支上最后 commit 的内容的差别
4.1 git diff branch1 branch2 --stat :显示出所有有差异的文件(不详细,没有对比内容)
4.2 git diff branch1 branch2 显示出所有有差异的文件的详细差异(更详细)
4.3 git diff branch1 branch2 具体文件路径: 显示指定文件的详细差异(对比内容)
4.4 git log dev ^master 查看 dev中log有的commit,而 master中log没有的commit
git HEAD^和git HEAD~
^:表示第几个父/母亲,git存在多个分支合并的情况,所以不只有1对父母亲
~:表示向上找第几代,相当于连续几个 ^
^x:抬头走1步,入x号岔路口。
~y:低头走y步,无视岔路口。
b1(HEAD)
|
C4 ------ C6
/
--- C5
自己: C6 = HEAD^0 = HEAD~0 = C6^0 = C6~0
父亲: C4 = HEAD^1 = HEAD^ = HEAD~1 = HEAD~ = C6^1 = C6^ = C6~1 = C6~
母亲: C5 = HEAD^2 = C6^2
git revert 重置
- git revert是用一次新的commit来回滚之前的commit,git reset是直接删除指定的commit。
- 在回滚这一操作上看,效果差不多。但是在日后继续merge以前的老版本时有区别。因为git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch时,导致这部分改变不会再次出现,但是git reset是之间把某些commit在某个branch上删除,因而和老的branch再次merge时,这些被回滚的commit应该还会被引入。
- git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,能够抵消要被revert的内容
git checkout 检出命令
用于切换分支或恢复工作树文件,同时也是一个很危险的命令,因为这条命令会重写工作区;在切换分支的时候,HEAD也会相应的指向对应的分支引用
命令 | 含义 |
---|---|
git checkout [-q] [] [–] … | 。。。。 |
git checkout [] | 。。。。 |
git checkout [-m] [ [-b ] [ – orphan ] <new_branch>] | 。。。。 [start_point] |
用法2比用法1的区别在于,用法1包含了路径。为了避免路径和引用(或提交ID)同名而发生冲突,可以在前用两个连续的连字符作为分隔。用法1的是可选项,如果省略,则相当于从暂存区进行检出覆盖工作区。既可以是某一个具体的commit hash值,也可以是某个分支名称,tag名称。不论分支也好,tag也好,它们本质上对应的都是一个commit hash值,第1种用法(包含的用法)不会改变HEAD头指针,主要使用于指定版本的文件覆盖工作区中对应的文件。如果省略,则会用暂存区的文件覆盖工作区中的文件,否则用指定提交中的文件覆盖暂存区和工作区中的对应文件。
实战2:创建新分支相关操作
1.git branch dev //创建分支dev
2.git checkout dev //切换到dev分支
Switched to branch 'dev'
3.git status //查看状态
On branch dev
nothing to commit, working directory clean
4.git branch -m dev dev2 //修改分支dev为dev2
5.git status //查看状态
On branch dev2
nothing to commit, working directory clean
6.git branch --delete dev2 //删除失败,因为现在正在处于检出状态
error: Cannot delete branch 'dev2' checked out at 'E:/data/'
7.git checkout master //切换到主分支
git branch -d dev2 //删除另一分支
Deleted branch dev2 (was efc6edb).
//在dev分支添加了修改,并合并到主分支
8.git checkout master //切换到master分支
git merge dev //把dev分支合并到master分支
Updating efc6edb..2b6ce3c
Fast-forward
README.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 README.md
实战3:分支及文件的删除和恢复
版本库中存在的可通过git checkout恢复工作空间误删文件,回滚历史的暂存区和工作空间的修改,可使用git reset和git revrert
1.git reset HEAD^ //HEAD表示当前指针,^表示上一次提交,默认只重置暂存区,工作区文件不修改
Unstaged changes after reset:
M README.md
2.git status //执行发现工作区文件不修改,暂存区log少一
3.git reset --hard HEAD^
4.git status //执行发现工作区文件修改,暂存区log少一
5.git revert HEAD //返回上一次,提交内容
[master 16beee1] Revert "add good3"
1 file changed, 1 insertion(+), 2 deletions(-)
6.git status //执行发现工作区文件修改,暂存区log加一
7.git rm README.md //删除
8.git status // 查看状态
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: README.md
9.git reset HEAD README.md //重置暂存区到上一次状态
Unstaged changes after reset:
D README.md
10. git status // 查看状态
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: README.md
11.git checkout -- README.md //--表示当前分支,恢复文件
12.8-11可用 git checkout HEAD -- filename 实现
git 提交到远程仓库
//添加远程库
git remote add origin https://github.com/user/repository.git
//显示出详细的url地址名和对应的别名
git remote -v
//移除命令
git remote remove
//从本地向指定的远程库推送,-u 跟踪分支变化
git push -u origin
实战4:本地仓库添加到远程仓库
//加入远程库
1.git remote add origin https://github.com/user/repository
2.git remote -v //显示
origin https://github.com/user/repository.git (fetch)
origin https://github.com/user/repository.git (push)
3.git push -u origin master //提交
4.输入用户名和密码:
git fetch,git pull
命令 | 含义 |
---|---|
git fetch | 从远程获取最新到本地,不会自动merge |
git pull | 从远程获取最新版本并merge到本地 |
实战5:远程仓库更新到本地仓库
//方法一
git fetch origin master //从远程的origin仓库的master分支下载代码到本地的origin master
git log -p master.. origin/master //比较本地的仓库和远程参考的区别
git merge origin/master //把远程下载下来的代码合并到本地仓库,远程的和本地的合并
//或者fetch完会在本地返回一个FETCH_HEAD
git log -p FETCH_HEAD //查看是否有冲突
git merge FETCH_HEAD
//方法二
git fetch origin master:temp //从远程的origin仓库的master分支下载到本地并新建一个分支temp
git diff temp //比较master分支和temp分支的不同
git merge temp //合并temp分支到master分支
git branch -d temp //删除temp
//git pull
git pull <远程主机名> <远程分支名>:<本地分支名>
实战6:git工程管理master和dev分支
命令 | 含义 |
---|---|
master分支 | 用于存放软件的稳定版本 |
dev分支 | 用于存放开发的版本 |
git push origin dev:dev | 把本地的dev分支发布到了远程仓库 |
git checkout master // 在合并之前切换到master分支
git merge dev //把dev分支的代码合并到master分支上
git push //提交刚刚的操作到远端github仓库
git checkout dev //切回dev分支进行下一步的开发
- tag是git版本库的一个标记,指向某个commit的指针。
- tag主要用于发布版本的管理,一个版本发布之后,我们可以为git打上 v.1.0.1 v.1.0.2 …这样的标签。
- 创建tag
创建 tag 是基于本地分支的commit,而且与分支的推送是两回事,就是说分支已经推送到远程了,但是你的 tag 并没有,如果把 tag 推送到远程分支上,需要另外执行 tag 的推送命令。
git tag <tagName> //创建本地tag
git push origin <tagName> //推送到远程仓库
git push origin --tags //若存在很多未推送的本地标签,你想一次全部推送的话
以上是基于本地当前分支的最后的一个commit创建的tag,但是如果不想以最后一个,只想以某一个特定的提交为tag,也是可以的,只要你知道commit 的id。
git log --pretty=oneline //查看当前分支的提交历史 里面包含 commit id
git tag -a <tagName> <commitId>
- 查看标签
git show <tagName> //查看本地某个 tag 的详细信息:
git tag 或者 git tag -l //查看本地所有 tag:
git ls-remote --tags origin //查看远程所有 tag:
- 删除标签
git tag -d <tagName> //本地 tag 的删除
git push origin :<tagName> //远程 tag 的删除
- 检出标签
因为 tag 本身指向的就是一个commit,所以和根据commitid检出分支是一个道理。但是需要特别说明的是,如果我们想要修改tag检出代码分支,那么虽然分支中的代码改变了,但是 tag标记的 commit还是同一个,标记的代码是不会变的,这个要格外的注意。
git checkout -b <branchName> <tagName>
git tag -a <tagname> -m "XXX..." //可以指定标签信息。
git tag -a v0.1.0 -m "release 0.1.0 version" //创建附注标签。
git checkout [tagname] //切换标签
问题
- (HEAD detached from efc6edb)
dev
master
使用git checkout id切换到指定的某一次提交,HEAD 就会处于 detached 状态(游离状态),有时候HEAD不会指向任何分支,严谨的说是HEAD指向了一个没有分支名字的修订版本,已经处于detached HEAD.这时候我们在进行commit操作不会提交到任何分支上去
解决办法:
(1)新建一个临时分支
(2)checkout 出要回到的那个分支
(3)合并分支
(4)删除临时创建的分支
(1)git remote rm origin
(2)git remote add origin https://github.com/user2/repository
ssh-keygen -t rsa -C “youremail@example.com”
一路回车 使用默认值即可,git会帮你生成id_rsa和id_rsa.pub两个文件,
在服务器添加完公钥后报错
sign_and_send_pubkey: signing failed: agent refused operation
1
这个时候我们只要执行下
eval “$(ssh-agent -s)”
ssh-add
! [rejected] master -> master (fetch first)
error: 无法推送一些引用到 ‘git@github.com:shuailisha/git_share.git’
提示:更新被拒绝,因为远程版本库包含您本地尚不存在的提交。这通常是因为另外
提示:一个版本库已推送了相同的引用。再次推送前,您可能需要先合并远程变更
提示:(如 ‘git pull’)。
提示:详见 ‘git push –help’ 中的 ‘Note about fast-forwards’ 小节。
解决方案:
因为当前分支的最新提交落后于其对应的远程分支,所以我们先从远程库fetch到更新再和本地库合并,之后就可以git push操作了。
git fetch origin
git merge origin/master