Git 是一个开源的分布式版本控制系统,能敏捷高效地处理任何或小或大的项目,通常用于团队开发项目过程中对源码协同编辑和管理。Git 是 Linus Torvalds 在2005年为了帮助管理 Linux 内核开发,基于C开发的一个开源版本控制软件,方便其它内核开发者提交贡献和修改。什么是版本控制系统?比如用word写论文,每次修改重新保存另一个文件,最后会出现很多版本,如果导师再修改还需要来回发送文件合并新内容,这样会很麻烦。Git可以自动记录每次文件的改动,支持对文件的协同编辑,就不需要手动管理多个“版本”。
其它版本控制工具 CVS, Subversion 均为集中式版本控制系统,版本库是集中存放在中央服务器的,个人从服务器中取得最新版本,修改结束后推送回中央服务器,类比图书馆,集中式版本控制系统需要连接网络才能工作。分布式版本控制系统没有“中央服务器”,每个人的电脑上都是一个完整的版本库,因此也不需要连接网络,安全性也很高。目前还有很多其它的版本控制系统,比如CVS, SVN, ClearCase等,Git是最流行的。
Git 目前支持 Linux/Unix、Solaris、Mac和 Windows 平台上运行,可在git-scm官网上下载。以windows系统为例,gitforwindows镜像下载,安装后包括图形界面Git GUI和Git Bash
git config --list
配置你的服务器的信息,git是分布式版本控制系统,因此每台机器需要设置用户名和邮件,使用global表明这台机器上的所有Git仓库都使用这个配置信息,也可以对某个仓库指定不同的用户名和邮件
$ git config --global user.name 'name'
$ git config --global user.email 'email'
# 查看config
$ git config --list
git init
:初始化目录git add
:添加文件git commit
:提交文件版本库也成为仓库(repository),相当于一个目录,这个目录里的所有文件都有能用Git管理,每个文件的修改历史都可以被追踪或还原。首先创建一个空目录mkdir
,进入该文件cd
,pwd
显示当前目录,通过git init
将这个目录变成Git可以管理的仓库,目录下会增加一个.git
目录,用于Git跟踪管理版本库。如果没看到可能是隐藏了,用ls -ah
可以看见
$ mkdir Desktop/learngit
$ cd Desktop/learngit
$ pwd
/c/Users/pengy/Desktop/learngit
$ git init
Initialized empty Git repository in C:/Users/pengy/Desktop/learngit/.git/
$ ls -ah
./ ../ .git/
接着在learngit里面建立一个readme.txt文件,直接新建文件,然后通过git add
和git commit
将该文件提交到仓库。add
告诉Git,将文件添加到仓库,可以反复使用,添加多个文件,commit
将文件提交到仓库,-m
是本次提交的说明。执行成功后会显示 1 file changed(一个文件被改动),2 insertions(+)(插入了两行内容)(readme.txt里的两行内容)。设置add
和commit
两步是因为commit
可以一次性提交多个很多文件,可以多次使用add
添加文件。
$ git add readme.txt
$ git commit -m 'wrote a readme file'
[master (root-commit) 643a68e] wrote a readme file
1 file changed, 2 insertions(+)
create mode 100644 readme.txt
go go go
run everyday
git status
:掌握仓库当前的状态git diff
:查看修改的内容git log
:查看从最近到最远的提交日志git reset
:回退到某个指定的版本git reflog
:查看命令历史,以便确定要回到未来的哪个版本修改readme.txt文件的内容,改成如下内容,用git status
命令查看结果
go go go
sleep everyday
$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
git status
可以让我们时刻掌握仓库当前的状态,上面结果表明,readme.txt被修改过了,但是还没有提交修改。如果想要查看具体修改的内容,用git diff
命令,可以看出将run修改为了sleep
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 9fbbc68..ab0fdda 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
go go go
-run everyday
\ No newline at end of file
+sleep everyday
\ No newline at end of file
接着用前面提到的方法提交修改
$ git add readme.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: readme.txt
$ git commit -m 'change sleep'
[master 3149571] change sleep
1 file changed, 1 insertion(+), 1 deletion(-)
$ git status
On branch master
nothing to commit, working tree clean
提交后显示没有需要提交的修改,工作目录working tree是干净。
按照前面的修改方法再修改文件如下
go go go
sleep everyday
young and rich
$ git add readme.txt
$ git commit -m 'append line'
[master 0efc261] append line
1 file changed, 2 insertions(+), 1 deletion(-)
这样对文件不停的修改,每次修改提交都会保留一个当前内容,方面后续恢复,如同备份,目前readme.txt已经修改了三次
go go go
run everyday
go go go
sleep everyday
go go go
sleep everyday
young and rich
用git log
查看从最近到最远的提交日志
$ git log
commit 0efc2612b8fbf89a036e4358c4a0c83f9afddffc (HEAD -> master)
Author: bujibujibiu <123456@gmail.com>
Date: Wed May 24 14:37:07 2023 +0800
append line
commit 3149571d74bc882218458f638eb119dae24e1a57
Author: bujibujibiu <123456@gmail.com>
Date: Wed May 24 14:26:39 2023 +0800
change sleep
commit 643a68e9294e906037cb37d3c120dac6f02a2127
Author: bujibujibiu <[email protected]>
Date: Wed May 24 11:31:55 2023 +0800
wrote a readme file
在图形化Git Gui中可以清楚看到提交历史
Git中Head
表示当前版本append line
,HEAD^
表示上一个,HEAD~100
表示上100个,用git reset
回退到上一个版本change sleep
,查看当前文件内容,变成了第二个版本
$ git reset --hard HEAD^
HEAD is now at 3149571 change sleep
$ cat readme.txt
go go go
sleep everyday
再次git log
会发现只有两条记录
$ git log
commit 3149571d74bc882218458f638eb119dae24e1a57 (HEAD -> master)
Author: bujibujibiu <[email protected]>
Date: Wed May 24 14:26:39 2023 +0800
change sleep
commit 643a68e9294e906037cb37d3c120dac6f02a2127
Author: bujibujibiu <[email protected]>
Date: Wed May 24 11:31:55 2023 +0800
wrote a readme file
如果想要回到最新的那个版本,就找到commit id
,版本号写前几位,Git会自动寻找对应的版本,可以发现又回到最新的版本
$ git reset --hard 0efc
HEAD is now at 0efc261 append line
$ cat readme.txt
go go go
sleep everyday
young and rich
为了找到版本号,可以用git reflog
记录每一次的命令
$ git reflog
0efc261 (HEAD -> master) HEAD@{0}: reset: moving to 0efc
3149571 HEAD@{1}: reset: moving to HEAD^
0efc261 (HEAD -> master) HEAD@{2}: commit: append line
3149571 HEAD@{3}: commit: change sleep
643a68e HEAD@{4}: commit (initial): wrote a readme file
在前文中提到过提交修改文件需要通过add和commit两步,流程如下,工作区是电脑里能看到的目录,版本库(Repository)是文件夹里的隐藏目录.git
,不算工作区,Git版本库中包含一个暂存区(index/stage),还有Git自动创建的第一个分支master
,以及指向master
的一个指针叫HEAD
。git add
将文件修改添加到暂存区,git commit
把暂存区的所有内容提交到当前分支master
。
比如在readme.txt里增加一行内容,同时新建文件LICENSE.txt,git status
表明修改了一个文件,新增了一个文件为Untracked files。然后git add
这两个文件,LICENSE.txt和readme.txt被放到了暂存区,git commit
将两个文件提交到master
分支
$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: readme.txt
Untracked files:
(use "git add ..." to include in what will be committed)
LICENSE.txt
no changes added to commit (use "git add" and/or "git commit -a")
$ git add readme.txt
$ git add LICENSE.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
new file: LICENSE.txt
modified: readme.txt
$ git commit -m 'stage works'
[master 2312846] stage works
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 LICENSE.txt
$ git status
On branch master
nothing to commit, working tree clean
Git管理的是每一次修改,比如按照下面操作:修改readme.txt—add—修改readme.txt—commit—status,commit提交的只是第一次修改的内容,add将第一次修改放在暂存区,可见Git管理的是每一次修改,而不是文件本身。
# (1)修改readme.txt,新增track changes
$ cat readme.txt
go go go
sleep everyday
young and rich
crzay life
track changes
# (2)readme.txt存放在暂存区
$ git add readme.txt
# (3)再次修改readme.txt,变成track changes second
$ cat readme.txt
go go go
sleep everyday
young and rich
crzay life
track changes second
# (4)提交暂存区里的readme.txt
$ git commit -m 'track changes'
[master bd56840] track changes
1 file changed, 2 insertions(+), 1 deletion(-)
# (5)显示当前状态,第二次修改的readme.txt没有被提交
$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
用git diff HEAD -- readme.txt
可以看到工作区和版本库里的readme.txt区别
$ git diff HEAD -- readme.txt
diff --git a/readme.txt b/readme.txt
index a8981d7..a7d5c05 100644
--- a/readme.txt
+++ b/readme.txt
@@ -2,4 +2,4 @@ go go go
sleep everyday
young and rich
crzay life
-track changes
\ No newline at end of file
+track changes second
\ No newline at end of file
git checkout -- file
:撤销file工作区的修改git reset HEAD file
:撤销暂存区的修改如果要撤销对工作区的修改,使用git checkout -- file
# (1)readme.txt文件新增stupid day
$ cat readme.txt
go go go
sleep everyday
young and rich
crzay life
track changes second
no hope
stupid day
# (2)删除工作区的修改
$ git checkout -- readme.txt
#(3)stupid day已经删除
$ cat readme.txt
go go go
sleep everyday
young and rich
crzay life
track changes second
no hope
如果已经add
到暂存区,使用git reset
命令把暂存区的修改回退到工作区,再用checkout
丢弃工作区的修改
# (1)修改readme.txt新增stupid day
$ cat readme.txt
go go go
sleep everyday
young and rich
crzay life
track changes second
no hope
stupid day
# (2)add到暂存区,状态为待提交
$ git add readme.txt
$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: readme.txt
# (3)把暂存区的修改回退到工作区,状态为待add
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
# (4)checkout撤销工作区的修改
$ git checkout -- readme.txt
$ cat readme.txt
go go go
sleep everyday
young and rich
crzay life
track changes second
no hope
已经提交了不合适的修改到版本库时,想要撤销本次提交,可使用前面的版本回退,不过前提是没有推送到远程库
git rm
:删除文件git checkout -- file
:恢复工作区file文件假设新增一个文件并提交到了版本库,现在需要删除这个文件,首先用rm
删除工作区中的文件,然后用使用git rm
删除版本库中文件
# (1)新增文件test.txt,并add和commit到版本库
$ git add test.txt
$ git commit -m 'add test.txt'
[master 33f52c0] add test.txt
1 file changed, 1 insertion(+)
create mode 100644 test.txt
# (2)使用rm命令直接删除工作区的test.txt
$ rm test.txt
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
deleted: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
# (3)使用git rm删除版本库中的test.txt并commit
$ git rm test.txt
rm 'test.txt'
$ git commit -m 'delete test.txt'
[master 2e755a3] delete test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt
如果用rm
删除了工作区中的某个文件,但是发现删错了,可以通过checkout
用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”
# (1)新增文件test.txt,并add和commit到版本库
$ git add test.txt
$ git commit -m 'add test new'
[master 943447f] add test new
1 file changed, 1 insertion(+)
create mode 100644 test.txt
# (2)使用rm命令直接删除工作区的test.txt
$ cat test.txt
for test
$ rm test.txt
$ cat test.txt
cat: test.txt: No such file or directory
# (3)checkout 恢复工作区的文件
$ git checkout -- test.txt
$ cat test.txt
for test
Git是一种分布式版本控制工具,用于管理多版本项目。Github和Gitlab都是基于git的代码托管平台,Github一般用于托管开源项目,GitLab比较私密,适合企业。本地仓库可以和远程仓库之间传输需要SSH加密。以github为例。首先在本地Git配置config信息,在Github上用该邮件注册账号。
$ git config --global user.name 'name'
$ git config --global user.email 'email'
先通过cd ~/.ssh
查看是否已经配置SSH,如果没有任何文件,则输入一下内容配置SSH,一直回车,密码可以不设置
$ ssh-keygen -t -rsa -C '[email protected]'
Generating public/private rsa key pair.
重新打开.ssh
目录,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以公开,将id_rsa.pub
内容复制到Github的SSH key设置中
$ cd ~/.ssh
$ ls
id_rsa id_rsa.pub
$ cat id_rsa.pub
判断是否连接成功,输入下面语句显示You’ve successfully authenticated, but GitHub does not provide shell access
$ ssh [email protected]
git remote add origin *********.git
:连接远程仓库git push
:将本地分支的内容推送到远程库git remote -v
:查看远程仓库信息git remote rm
:删除远程仓库如果通过前面的3.1创建本地仓库后,想要在GIthub或者Gitlab中也创建一个Git仓库,并且两个仓库远程同步,首先在GIthub中Create repository创建一个空的Git仓库,然后,把本地仓库的内容推送到GitHub仓库,在本地的仓库下运行命令
$ git remote add origin *********.git
*********
就是你的远程仓库地址,添加后,远程库的名字就是origin
,这是Git默认的叫法。用git remote -v可以查看远程库信息
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/CPCS (master)
$ git remote -v
origin https://github.com/bujibujibiu/learngit.git (fetch)
origin https://github.com/bujibujibiu/learngit.git (push)
如果添加的时候地址写错了,或者就是想删除远程库,可以用git remote rm
命令
$ git remote rm origin
把本地库的所有内容推送到远程库上用git push
,这样matser
分支的内容就推送到Github中,以后每次修改都可以通过这个命令更新远程仓库
$ git push origin master
如果是远程库和本地库都初始化了,现在需要同步,那么首先要将远程库pull到本地,然后push。
$ git pull origin master
出现fatal: refusing to merge unrelated histories错误就用下面方法强制合并
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit(master)
$ git pull origin master --allow-unrelated-histories
From https://github.com/bujibujibiu/learngit
* branch master -> FETCH_HEAD
Merge made by the 'ort' strategy.
README.md | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 README.md
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit(master)
$ git push origin master
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 12 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (8/8), 95.42 KiB | 13.63 MiB/s, done.
Total 8 (delta 1), reused 0 (delta 0), pack-reused 0
To https://github.com/bujibujibiu/learngit.git
7ec29b2..fb58fc0 master -> master
git clone *****
:克隆远程库至本地文件4.2是先有本地仓库,后有远程仓库,如何关联远程库,假设现在先有远程仓,需要克隆到本地。比如首先创建Github仓库,勾选Initialize this repository with a README
,这样GitHub会自动为创建一个README.md
文件。下一步是用命令git clone
克隆一个本地库。
$ git clone https://github.com/bujibujibiu/learngit.git
这样本地就会出现一个learngit的库,并且有README.md
文件
git branch
:查看分支git branch name
:新建分支git checkout (branchname)
:切换分支命令git checkout -b (branchname)
:创建新分支并立即切换到该分支Git管理修改是将这些提交串成时间线,也就是一个分支,在Git初始化时自动创建了一个分支master
,当前版本HEAD
指向master
,master
指向最新的提交点。每次提交,master
分支都会向前移动一步,随着不断提交,master
分支的线也越来越长。如果创建新的分支比如dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上。从现在开始,对工作区的修改和提交就是针对dev
分支了,比如新提交一次后,dev
指针往前移动一步,而master
指针不变。
如下:创建文件夹learngit,通过3.1的操作新建仓库并添加readme.txt文件
$ cd learngit
$ git init
Initialized empty Git repository in C:/Users/pengy/Desktop/learngit/.git/
$ git status
On branch master
No commits yet
Untracked files:
(use "git add ..." to include in what will be committed)
readme.txt
nothing added to commit but untracked files present (use "git add" to track)
$ git add .
$ git commit -m 'create readme file'
[master (root-commit) dd8bad0] create readme file
1 file changed, 6 insertions(+)
create mode 100644 readme.txt
$ git status
On branch master
nothing to commit, working tree clean
$ git branch
* master
然后新建分支test
,切换到test
分支
~/Desktop/learngit (master)
$ git branch test
~/Desktop/learngit (master)
$ git branch
* master
test
~/Desktop/learngit (master)
$ git checkot test
git: 'checkot' is not a git command. See 'git --help'.
The most similar command is
checkout
~/Desktop/learngit (master)
$ git checkout test
Switched to branch 'test'
在test
分支下新增文件夹test.txt,ls
发现在test
分支下有两个文件readme.txt和test.txt,再切回到master
分支,只剩下readme.txt文件
~/Desktop/learngit (test)
$ ls
readme.txt
~/Desktop/learngit (test)
$ echo 'runoob.com' > test.txt
~/Desktop/learngit (test)
$ ls
readme.txt test.txt
~/Desktop/learngit (test)
$ git add .
warning: in the working copy of 'test.txt', LF will be replaced by CRLF the next time Git touches it
~/Desktop/learngit (test)
$ git commit -m 'add test file'
[test d20d68d] add test file
1 file changed, 1 insertion(+)
create mode 100644 test.txt
~/Desktop/learngit (test)
$ ls
readme.txt test.txt
~/Desktop/learngit (test)
$ git checkout master
Switched to branch 'master'
~/Desktop/learngit (master)
$ ls
readme.txt
使用git checkout -b (branchname)
新建分支newtest
并切换到该分支,文件和master
一样
~/Desktop/learngit (master)
$ git checkout -b newtest
Switched to a new branch 'newtest'
~/Desktop/learngit (newtest)
$ ls
readme.txt
git branch -d (branchname)
:删除分支使用git branch -d (branchname)
删除前面新建的newtest
分支,注意要切换到别的分支,不能删除当前所在分支
~/Desktop/learngit (newtest)
$ git branch
master
* newtest
test
~/Desktop/learngit (newtest)
$ git branch -d newtest
error: Cannot delete branch 'newtest' checked out at 'C:/Users/pengy/Desktop/learngit'
~/Desktop/learngit (newtest)
$ git checkout master
Switched to branch 'master'
~/Desktop/learngit (master)
$ git branch -d newtest
Deleted branch newtest (was dd8bad0).
~/Desktop/learngit (master)
$ git branch
* master
test
git merge (branchname)
:将任何分支合并到当前分支中(可以不是主分支)在master
分支中新建文件runoob.php,并且commit
,这样master
分支中有两个文件readme.txt和runoob.php,test
分支中有两个文件readme.txt和test.txt
~/Desktop/learngit (master)
$ git branch
* master
test
~/Desktop/learngit (master)
$ touch runoob.php
~/Desktop/learngit (master)
$ git add .
~/Desktop/learngit (master)
$ git commit -m 'add runoob file'
[master 3dcca8c] add runoob file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 runoob.php
~/Desktop/learngit (master)
$ ls
readme.txt runoob.php
~/Desktop/learngit (master)
$ git checkout test
Switched to branch 'test'
~/Desktop/learngit (test)
$ ls
readme.txt test.txt
合并test
分支到master
分支中,假设两个分支下都有test.txt文件且不一样,合并会产生冲突
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (test)
$ cat test.txt
runoob.com
study
new
amazing
HAPPY
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (master)
$ cat test.txt
runoob.com
study
new
new again
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (master)
$ git merge test
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
打开test.txt会看到冲突内容
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (master|MERGING)
$ cat test.txt
runoob.com
study
new
<<<<<<< HEAD
new again
=======
amazing
HAPPY
>>>>>>> test
Git通常会在进行合并操作时生成MERGE_MSG交换文件,以保存合并消息的内容。如果Git在工作目录下找到了这个交换文件,说明上一次的合并操作没有成功完成,编辑器的进程可能意外终止。输入
rm .git/.MERGE_MSG.swp
根据提示修改master
分支下的test.txt文件,重新commit
后显示[master 2bf0895]表示成功
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add ..." to mark resolution)
both modified: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (master|MERGING)
$ git add .
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (master|MERGING)
$ git commit -m 'merge change'
[master 2bf0895] merge change
pengy@LAPTOP-7A77J86V MINGW32 ~/Desktop/learngit (master)
$ git status
On branch master
nothing to commit, working tree clean