Git
Git
1.基础
①版本控制
-
在使用word写论文的时候,为了重复率不得不删除某段,查重完成之后发现重复率远远低于红线,于是又想要找回原来的那段。但是论文的版本过多,很难找到是哪个版本的。于是,想拥有一个软件,可以记录各个版本。
-
集中式版本控制,需要一个中央服务器,只有中央服务器上拥有完整的版本库。每次干活从中央服务器中下载项目,改完了在上传上去。缺点:需要联网,如果项目过大,网速又不给力,将浪费时间。此外,中央服务器出现故障,将造成严重后果。
-
分布式版本控制,每个人的电脑都是完整的版本库,无需联网。当然,在多人协作时,也需要一个中央服务器,双方对同一个项目同一个版本做完修改后,可以通过该中央服务器传递各自的修改内容。
②版本库
版本库(repository)又名仓库,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
-
创建一个空目录。
-
通过
git init命令把这个目录变成Git可以管理的仓库。$ git init Initialized empty Git repository in /Users/michael/learngit/.git/ -
将文件放入仓库中:
$ git add readme.txt。 -
提交:
git commit -m "wrote a readme file",-m后面输入的是本次提交的说明。
2.远程仓库
①SSH
- SSH(Secure Shell),与https中的SSL类似,SSH也是一种协议,采用的非对称加密。
- 指定用户名:
$ git config --global user.name "fangpeng" - 指定邮箱:
$ git config --global user.email "279948813@qq.com" - Git客户端生成密钥对命令:
ssh-keygen -t rsa -C "xxx@xxx.com"。会在主目录生成两个文件,id_rsa.pub是公钥,id_rsa是私钥。终端输入open ~/.ssh打开主目录。 - 将公钥配置到gitlab服务器上。

公钥加密必须由私钥解密,私钥加密必须由公钥解密。
②操作
同步:
- 在gitlab、github、coding等远程仓库管理软件上创建好一个远程仓库。
- 本地仓库执行命令:
git remote add origin git@gitlab.com:fangpeng8/learngit.git,其中@gitlab.com:fangpeng8/learngit.git可以成功定位到远程仓库。 - 关联成功后,就可以push/pull了。命令
$ git push -u origin master就是把本地库推送到远程。第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的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 remote rm <name>命令。使用前,建议先用git remote -v查看远程库信息:
$ git remote -v
origin git@github.com:michaelliao/learn-git.git (fetch)
origin git@github.com:michaelliao/learn-git.git (push)
然后,根据名字删除,比如删除origin:
$ git remote rm origin
此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到GitHub,在后台页面找到删除按钮再删除。
③克隆
假设从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
用命令git clone克隆一个本地库:
$ git clone git@github.com:michaelliao/gitskills.git
3.版本管理
①版本状态
-
命令
git status查看当前版本修改状态:$ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: readme.txt no changes added to commit (use "git add" and/or "git commit -a")可以看到readme.txt被修改了,还没有被提交。
-
命令
git diff查看某文件的差异$ git diff readme.txt diff --git a/readme.txt b/readme.txt index 46d49bf..9247db6 100644 --- a/readme.txt +++ b/readme.txt @@ -1,2 +1,2 @@ -Git is a version control system. +Git is a distributed version control system. Git is free software.
②版本回退
-
强制回到某个版本,目前所做的修改都丢弃:
git reset --hard 版本号 文件名 -
回到某个版本,目前所做的修改不丢弃:
git reset --soft 版本号 文件名 -
不断对文件进行修改,然后不断提交修改到版本库里,就好比玩RPG游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss之前,你会手动存盘,以便万一打Boss失败了,可以从最近的地方重新开始。
-
Git也是一样,每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为
commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。 -
命令
git log查看版本的提交记录$ git log commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 21:06:15 2018 +0800 append GPL commit e475afc93c209a690c39c13a46716e8fa000c366 Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 21:03:36 2018 +0800 add distributed commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 Author: Michael Liao <askxuefeng@gmail.com> Date: Fri May 18 20:59:18 2018 +0800 wrote a readme file如果嫌输出信息太多,看得眼花缭乱的,可以试试加上
--pretty=oneline参数:$ git log --pretty=oneline 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL e475afc93c209a690c39c13a46716e8fa000c366 add distributed eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file -
在Git中,用
HEAD表示当前版本,也就是最新的提交1094adb...,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。 -
使用命令
$ git reset --hard HEAD^,将当前版本append GPL回退到上一个版本add distributed。 -
版本回退后,又后悔了,返现上个版本的一些修改还是有用的,想要找回来。使用
git log发现最新的那个版本append GPL已经看不到了!好比你从21世纪坐时光穿梭机来到了19世纪,想再回去已经回不去了。办法其实还是有的,只要上面的命令行窗口还没有被关掉,你就可以顺着往上找啊找啊,找到那个
append GPL的commit id是1094adb...,于是就可以指定回到未来的某个版本:$ git reset --hard 1094a HEAD is now at 83b0afe append GPL版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。
-
如果上面的命令窗口关闭了,无法找到上个版本的版本号,还是有后悔药的。Git提供了一个命令
git reflog用来记录你的每一次命令:$ git reflog e475afc HEAD@{1}: reset: moving to HEAD^ 1094adb (HEAD -> master) HEAD@{2}: commit: append GPL e475afc HEAD@{3}: commit: add distributed eaadf4e HEAD@{4}: commit (initial): wrote a readme file可以通过这个命令找到版本号。
③暂存区
工作区、版本库、暂存区三者的关系
-
工作区:电脑上能看到的目录。
$ git status查看的就是工作区的状态 -
版本库(repository):存放在隐藏目录.git文件中。包含了暂存区、第一个分支(master)和指向master的一+ 个指针HEAD。
-
暂存区(stage):暂时存放文件的地方。把文件往Git版本库里添加的时候,是分两步执行的,用
git add把文件添加进去,实际上就是把文件修改添加到暂存区;用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。 -
如果一个文件修改了,没有
git add,而是直接git commit,那么这个文件的修改不会被提交,因为其没有被放到暂存区。

总结
-
将单个文件从工作区加到暂存区:
git add + 文件名 -
将多个文件从工作区加到暂存区:
git add + 文件名1 文件名2 -
将多有文件从工作区加到暂存取:
git add all
④撤销修改
-
未
git add到stage:$ git checkout -- readme.txt。把readme.txt文件在工作区的修改全部撤销。这里有两种情况:一种是
readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;一种是
readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。总之,就是让这个文件回到最近一次
git commit或git add时的状态。注意:该命令是
--。 -
已
git add到stage,未commit:$ git reset HEAD readme.txt。可以把暂存区的修改撤销掉(unstage),重新放回工作区。git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。 -
已commit,未push:
git reset -head HEAD^回退版本。
总结:
- 文件修改后未放置到暂存区,从版本库中获取:
git checkout -- 文件名 - 文件添加至暂存区,又作出修改,撤销至暂存区状态:
git checkout -- 文件名
这里的checkout其实是用版本库里的版本替换工作区的版本,无论修改还是删除,都可以进行还原。
⑤删除文件
-
一般情况下,通常直接在文件管理器中把没用的文件删了
-
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,
git status命令会立刻告诉你哪些文件被删除了:$ 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: test.txt no changes added to commit (use "git add" and/or "git commit -a") -
确实要从版本库中删除该文件,那就用命令
git rm删掉,并且git commit。$ git rm test.txt rm 'test.txt' $ git commit -m "remove test.txt" [master d46f35e] remove test.txt 1 file changed, 1 deletion(-) delete mode 100644 test.txt -
如果是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本。
$ git checkout -- test.txtgit checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
4.分支管理
https://blog.csdn.net/qq_37772867/article/details/104924533
①创建与合并
概念:
在版本回退里,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

命令:
-
创建
dev分支,然后切换到dev分支:$ git checkout -b dev,加上-b相当于以下两条命令:$ git branch dev $ git checkout dev Switched to branch 'dev' -
查看当前分支:
$ git branch * dev master -
切换分支,
dev分支的工作完成,我们就可以切换回master分支:$ git checkout master Switched to branch 'master'

切换回master分支后,再查看文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变
-
把
dev分支的工作成果合并到master分支上:$ git merge dev Updating d46f35e..b17d20e Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+)git merge命令用于合并指定分支到当前分支。 -
合并完成后,就可以放心地删除
dev分支:$ git branch * master -
注意到切换分支使用
git checkout <branch>,前面的撤销修改则是git checkout -- <file>,同一个命令,有两种作用,确实有点令人迷惑。实际上,切换分支这个动作,用
switch更科学。因此,最新版本的Git提供了新的git switch命令来切换分支:创建并切换到新的
dev分支,可以使用:$ git switch -c dev直接切换到已有的
master分支,可以使用:$ git switch master
②冲突
对于一个文件,两个分支都有了新的提交,如:master分支和feature1分支各自都分别有新的提交

Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突:
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
此时,可以在master分支再次对readme.txt文件进行修改再提交:

可以用带参数的git log也可以看到分支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
* cf810e4 (HEAD -> master) conflict fixed
|\
| * 14096d0 (feature1) AND simple
* | 5dc6824 & simple
|/
* b17d20e branch test
* d46f35e (origin/master) remove test.txt
* b84166e add test.txt
* 519219b git tracks changes
* e43a48b understand how stage works
* 1094adb append GPL
* e475afc add distributed
* eaadf4e wrote a readme file
③分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活。- 干活都在
dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本; - 我们每个人都在
dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

④多人协作
当从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote:
$ git remote
origin
或者,用git remote -v显示更详细的信息:
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
如果要推送其他分支,比如dev,就改成:
$ git push origin dev
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
抓取分支
多人协作时,大家都会往master和dev分支上推送各自的修改。
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@github.com:michaelliao/learngit.git
Cloning into 'learngit'...
remote: Counting objects: 40, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 40 (delta 14), reused 40 (delta 14), pack-reused 0
Receiving objects: 100% (40/40), done.
Resolving deltas: 100% (14/14), done.
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:
$ git add env.txt
$ git commit -m "add env"
[dev 7a5e5dd] add env
1 file changed, 1 insertion(+)
create mode 100644 env.txt
$ git push origin dev
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
f52c633..7a5e5dd dev -> dev
你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:
$ cat env.txt
env
$ 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"
[dev 57c53ab] fix env conflict
$ git push origin dev
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 621 bytes | 621.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
7a5e5dd..57c53ab dev -> dev
⑤Rebase
多人在同一个分支上协作时,很容易出现冲突。即使没有冲突,后push的童鞋不得不先pull,在本地合并,然后才能push成功。
每次合并再push后,分支变成了这样:
$ git log --graph --pretty=oneline --abbrev-commit
* d1be385 (HEAD -> master, origin/master) init hello
* e5e69f1 Merge branch 'dev'
|\
| * 57c53ab (origin/dev, dev) fix env conflict
| |\
| | * 7a5e5dd add env
| * | 7bd91f1 add new env
| |/
* | 12a631b merged bug fix 101
|\ \
| * | 4c805e2 fix bug 101
|/ /
* | e1e9c68 merge with no-ff
|\ \
| |/
| * f52c633 add merge
|/
* cf810e4 conflict fixed
总之看上去很乱,为什么Git的提交历史不能是一条干净的直线?
其实是可以做到的!
Git有一种称为rebase的操作,有人把它翻译成“变基”。
先不要随意展开想象。我们还是从实际问题出发,看看怎么把分叉的提交变成直线。
在和远程分支同步后,我们对hello.py这个文件做了两次提交。用git log命令看看:
$ 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,本地分支比远程分支快两个提交。
现在我们尝试推送本地分支:
$ git push origin master
To github.com:michaelliao/learngit.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
很不幸,失败了,这说明有人先于我们推送了远程分支。按照经验,先pull一下:
$ git pull
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
d1be385..f005ed4 master -> origin/master
* [new tag] v1.0 -> v1.0
Auto-merging hello.py
Merge made by the 'recursive' strategy.
hello.py | 1 +
1 file changed, 1 insertion(+)
再用git status看看状态:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
加上刚才合并的提交,现在我们本地分支比远程分支超前3个提交。
用git log看看:
$ git log --graph --pretty=oneline --abbrev-commit
* e0ea545 (HEAD -> master) Merge branch 'master' of github.com:michaelliao/learngit
|\
| * f005ed4 (origin/master) set exit=1
* | 582d922 add author
* | 8875536 add comment
|/
* d1be385 init hello
...
现在事情有点不对头,提交历史分叉了。如果现在把本地分支push到远程,有没有问题?
有!
什么问题?
不好看!
有没有解决方法?
有!
这个时候,rebase就派上了用场。我们输入命令git rebase试试:
$ git rebase
First, rewinding head to replay your work on top of it...
Applying: add comment
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
Applying: add author
Using index info to reconstruct a base tree...
M hello.py
Falling back to patching base and 3-way merge...
Auto-merging hello.py
输出了一大堆操作,到底是啥效果?再用git log看看:
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master) add author
* 3611cfe add comment
* f005ed4 (origin/master) set exit=1
* d1be385 init hello
...
原本分叉的提交现在变成一条直线了!这种神奇的操作是怎么实现的?其实原理非常简单。我们注意观察,发现Git把我们本地的提交“挪动”了位置,放到了f005ed4 (origin/master) set exit=1之后,这样,整个提交历史就成了一条直线。rebase操作前后,最终的提交内容是一致的,但是,我们本地的commit修改内容已经变化了,它们的修改不再基于d1be385 init hello,而是基于f005ed4 (origin/master) set exit=1,但最后的提交7e61ed4内容是一致的。
这就是rebase操作的特点:把分叉的提交历史“整理”成一条直线,看上去更直观。缺点是本地的分叉提交已经被修改过了。
最后,通过push操作把本地分支推送到远程:
Mac:~/learngit michael$ git push origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 576 bytes | 576.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To github.com:michaelliao/learngit.git
f005ed4..7e61ed4 master -> master
再用git log看看效果:
$ git log --graph --pretty=oneline --abbrev-commit
* 7e61ed4 (HEAD -> master, origin/master) add author
* 3611cfe add comment
* f005ed4 set exit=1
* d1be385 init hello
...
远程分支的提交历史也是一条直线。
5.IDEA
①开始
- 在coding、gitlab或github上建立一个远程仓库
- 在idea上创建一个项目,并设置远程仓库地址为远程仓库上的地址,一般为ssh地址
- 打开Terminal终端,输入命令
git init将该项目文件夹设置为git本地仓库,此时本地仓库有个默认的分支master - 使用IDEA完成一次commit和push,则远程仓库上会同步一个master分支与之对应
- 同理,如果想在远程仓库上有一个dev分支,现在本地创建一个dev分支,之后commit和push,则远程仓库上会同步一个dev分支与之对应
②Git-Amend
有时你提交过代码之后,发现一个地方改错了,你下次提交时不想保留上一次的记录
或者你上一次的commit message的描述有误
这时候你可以使用接下来的这个命令:git commit --amend
③GitIgnore
概念
在工程中,并不是所有文件都需要保存到版本库中的,例如“target”目录及目录下的文件就可以忽略。在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件或目录。
优先级
在 .gitingore 文件中,每一行指定一个忽略规则,Git 检查忽略规则的时候有多个来源,它的优先级如下(由高到低):
- 从命令行中读取可用的忽略规则
- 当前目录定义的规则
- 父级目录定义的规则,依次递推 $GIT_DIR/info/exclude 文件中定义的规则
- core.excludesfile中定义的全局规则
语法
- 空格不匹配任意文件,可作为分隔符,可用反斜杠转义
- 开头的文件标识注释,可以使用反斜杠进行转义
- ! 开头的模式标识否定,该文件将会再次被包含,如果排除了该文件的父级目录,则使用 ! 也不会再次被包含。可以使用反斜杠进行转义
- / 结束的模式只匹配文件夹以及在该文件夹路径下的内容,但是不匹配该文件
- / 开始的模式匹配项目跟目录
- 如果一个模式不包含斜杠,则它匹配相对于当前 .gitignore 文件路径的内容,如果该模式不在 .gitignore 文件中,则相对于项目根目录
- ** 匹配多级目录,可在开始,中间,结束
- ? 通用匹配单个字符
- *通用匹配零个或多个字符
- [] 通用匹配单个字符列表
常用匹配忽略
bin/: 忽略当前路径下的bin文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件
/bin: 忽略根目录下的bin文件
/*.c: 忽略 cat.c,不忽略 build/cat.c
debug/*.obj: 忽略 debug/io.obj,不忽略 debug/common/io.obj 和 tools/debug/io.obj
**/foo: 忽略/foo, a/foo, a/b/foo等
a/**/b: 忽略a/b, a/x/b, a/x/y/b等
!/bin/run.sh: 不忽略 bin 目录下的 run.sh 文件
*.log: 忽略所有 .log 文件
config.php: 忽略当前路径的 config.php 文件
我的忽略
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
/logs/
6.命令大全
①全局配置
-
让该文件夹变成本地git仓库:
git init -
查看所有的配置:
git config --list -
修改用户名:
git config --global user.name "fangpeng" -
查看用户名:
git config user.name -
修改邮箱:
git config --global user.email "279948813@qq.com" -
查看邮箱:
git config user.email -
查看远程库的url:
git remote -v -
让Git显示颜色:
git config --global color.ui true -
显示隐藏文件,如
.git版本库被隐藏:ls -ah
②查看状态
-
查看工作区文件的状态:
git status,-s可简短输出无文件改变
On branch dev nothing to commit, working tree clean有文件改变
On branch dev Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: src/main/java/com/fang/peng/learngit/LearnGitApplication.java -
查看工作区某修改后文件的差异:
git diff 文件名 -
查看版本库中各个版本:
git logcommit f51f25d81d1b7e0afc012be306f56bbe7cea6cca (HEAD -> dev, origin/dev) Author: fangpeng8 <fangpeng8@jd.com> Date: Wed Sep 22 20:23:48 2021 +0800 <E4><BF><AE><E6><94><B9> commit 719861948600666686af740d1683a56252cfeeff (origin/master) Author: fangpeng8 <fangpeng8@jd.com> Date: Wed Sep 22 19:46:36 2021 +0800 feat: <E5><88><9D><E5><A7><8B><E5><8C><96>省略版:
$ git log --pretty=oneline -
查看所有分支:
git branch -
查看所有分支:
git branch -a* dev master show remotes/origin/dev remotes/origin/master其中,带
*号的为当前分支 -
查看历史命令:
git reflogf51f25d (HEAD -> dev, origin/dev, show) HEAD@{0}: commit: <E4><BF><AE><E6><94><B9> 7198619 (origin/master) HEAD@{1}: checkout: moving from master to dev 69ec1a0 (master) HEAD@{2}: checkout: moving from dev to master 7198619 (origin/master) HEAD@{3}: checkout: moving from master to dev 69ec1a0 (master) HEAD@{4}: commit: <E5><BB><BA><E7><AB><8B>dev<E5><88><86><E6><94><AF> 7198619 (origin/master) HEAD@{5}: commit (initial): feat: <E5><88><9D><E5><A7><8B><E5><8C><96>可查看对哪些版本的哪些操作
-
将文件添加到stage中:
$ git add readme.txt -
将stage中的文件提交到当前分支:
$ git commit -m "wrote a readme file",-m后面输入的是本次提交的说明。 -
通过vi修改文件:vi有两种模式,一种是命令模式,一种是编辑模式。在命令模式下,输入i或者insert键进入编辑模式。在编辑模式下,可以通过ESC进入命令模式。命令模式下的常见指令:输入
:wq(注意冒号)、ZZ保存修改并退出vi。放弃所有修改:输入:q!+回车。 -
查看在你上次提交之后是否有对文件进行再次修改:
$ git status, -s 参数可获得简短输出。 -
查看工作区和版本库中最新版本的区别:
git diff HEAD -- readme.txt -
回退上个版本:
$ git reset --hard HEAD^、$ git reset --hard 1094a。1094a为目标版本号。 -
用版本库中的文件替换工作区的文件:
$ git checkout -- test.txt,无论工作区是修改还是删除,都可以“一键还原”。
③版本问题
在Git中,HEAD表示当前版本,HEAD表示上个版本,HEAD^表示上上个版本,往上一百个版本可以用HEAD~100表示。
回退版本
-
回退到上个版本:
$ git reset --hard HEAD^,HEAD^可以使用版本号代替。 -
回退之后,最新的那个版本有消失了,还可以
$ git reset --hard 1094a指定回到未来的版本,1094a是版本号,可以不用写全。 -
如果忘记了未来版本的版本号,可以通过
$ git reflog查看历史命令,从而获取版本号。
撤销修改
-
场景1:改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令
git checkout -- file。将该文件恢复到暂存区或者版本库中的版本。 -
场景2:不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令
git reset HEAD <file>,就回到了场景1,第二步按场景1操作。 -
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
-
场景4:推送到版本库中了,此时可以再次修改会原样,再推送。
删除文件
- 删除工作区的文件:
rm test.txt。如果该文件已经被commit了,将导致工作区和版本库不一致。此时有两种选择。将版本库中的文件也删除git rm test.txt,且提交commit;删错了,可以从版本库中恢复该文件git checkout -- test.txt。
git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
④远程仓库
- 将本地仓库和GitHub上的仓库合并,并且同步。先在GitHub上创建一个仓库。在本地仓库中输入以下命令:
$ git remote add origin git@github.com:fangpeng/learngit.git,其中fangpeng为GitHub的账户名。添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。 - 将本地仓库中的内容推送到远程库上。把本地库的内容推送到远程,
$ git push -u origin master,实际上是把当前分支master推送到远程。加上-u参数可以让本地的master分支和远程的master分支关联起来,在以后的推送和拉取时就可以简化命令。 - 查看远程库地址信息:
$ git remote -v删除远程库:$ git remote rm origin - 克隆远程库:
$ git clone git@github.com:fangpeng/learngit.git - 将远程仓库的分支拉下来:
git fetch,再合并git merge。这两个操作等同于git pull。
⑤分支管理
- 切换到
dev分支:$ git checkout dev - 创建并切换:
$ git checkout -b dev - 查看当前分支:
$ git branch - 将
dev分支合并到master分支:$ git merge dev - 删除
dev分支:$ git branch -d dev - 查看分支的合并情况:
$ git log --graph

浙公网安备 33010602011771号