Git(读音为/gɪt/。)是一个开源的分布式版本控制系统,可以有效、高速地处理从
很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核
开发而开发的一个开放源码的版本控制软件。
git整个工作流的whole picture可以参考下面这张图片:
图中的各部分分别表示:
一些基本概念:
$ cat .git/HEAD
ref: refs/heads/master # 当前指向master
第一步需要配置你的git用户信息
$ git config --global user.name "yourname"
$ git config --global user.email [email protected]
如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, git 都会使用那些信息。
当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运 行没有 --global 选项的命令来配置。
配置为之后,可以用以下命令查看:
git config --list
注意:github的提交记录,需要你本地配置的email被加入到了github设置中才会记录为有效提交。
详情参考:
Setting your commit email address on GitHub
Adding an email address to your GitHub account
Why are my contributions not showing up on my profile?
把普通目录改成用git管理的仓库。目录下会多了一个.git的目录,这个目录是git来跟踪管理版本的
$ git init
下面这几个命令是最最最常用,最最最基本的git命令,可以先走一遍流程。
git status # 查看目前文件夹git的状态
git add . # 将本地所有的修改添加到暂存区
# git checkout -- # 放弃对某个文件的修改
git commit -m "your description"
git push -u origin master # the first time with -u
# git push origin <要推送的本地分支名>
可以用log查看版本库的更新过程:
git log
# 查看各版本号及信息(所有的commit:本地commit + 其他同事的commit)
git log –pretty=oneline
git log --graph --pretty=oneline --abbrev-commit
# --pretty=oneline:一行显示,只显示哈希值和提交说明(--online本身也可以作为单独的属性)
# --abbrev-commit:仅显示SHA-1的前几个字符,而非所有的40个字符
人非圣贤孰能无过,在执行了不想执行的git add 或者 git commit 或者 git push操作,我们需要执行相应的撤销操作。
用命令git reset HEAD 可以把暂存区的修改撤销掉(unstage),重新放回工作区:
$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
git reset
命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本(上一个commit)。
git reset --hard HEAD # 撤销工作目录中所有未提交文件的修改内容
git checkout -- readme.txt # 撤销工作目录中制定的未提交文件的修改内容
意思就是,把readme.txt文件在工作区做的修改全部撤销,这里有2种情况
git reset HEAD # to unstage, 撤销git add
git checkout --
git checkout
其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。所以git checkout – [file] 是一个危险的命令。 你对那个文件做的任何修改都会消失 - 你只是拷贝了另一个文件来覆盖它。 除非你确实清楚不想要那个文件了,否则不要使用这个命令。
git reset --hard HEAD~1 # git reset --hard HEAD^
# 撤销之前的提交:
# 因为你使用了 --hard,所有你的文件将重置到上一次提交时的状态。
# uncommit for reworking: 去掉"--hard",这个对于非merge的commit有效,对于merge的commit最好删除merge后重新创建。
git reset --soft HEAD~1 # git reset --soft HEAD^
# 撤销提交但保留文件和索引:
# 从当前分支移除上一次commit,但是当前文件的修改会保留在你的工作区(working tree),同时暂存区(index)的修改也会保留。
# 此时直接用git commit就可以回到git reset之前的状态。
git reset HEAD~1 # git reset HEAD^
# 要撤销提交但保留更改:mixed mode,与soft mode非常像。
# 但是只把更改保留在工作区(working tree)而非暂存区(index),此时需要先git add然后git commit即可回到git reset之前的状态。
注意:git rest --hard HEAD~1
的操作非常危险,本地工作区如果有unstaged的修改就会丢失,所以在使用这个命令前一定要保证本地没有unstaged files
,即git status
是空的! 所幸:git reset --keep HEAD~1
可以作为git rest --hard HEAD~1
的安全版本。
如果某次commit后发现漏了一个文件,可以使用下面命令把这个文件加上上一次的commit中。
$ git add missing_file
$ git commit --amend --no-edit # "--no-edit": 不编辑, 直接合并到上一个 commit
$ git log --oneline # "--oneline": 每个 commit 内容显示在一行
对于已经push的版本,进行回退
# step 1,本地回退到指定的版本
git reset --hard 版本号
# step 2,将远程的也回退到指定版本
git push -f origin dev
# 回到上一个版本
git reset --hard HEAD^
# HEAD指向的版本就是当前版本
# 或者使用 git reset --hard HEAD~
# ------------------------------ #
# 如果想回退到100个版本:
git reset –-hard HEAD~100
# 本地回退到指定的版本
git reset --hard 版本号
# ------------------------------ #
# 查看以往版本号(本地的commit)
git log
# 如果要回到未来的版本可以用这个查看
git reflog
$ git fetch --all
$ git reset --hard origin/master
$ git pull
Git远程操作详解: git pull/git fetch/git push
等。
$ git pull <远程主机名> <远程分支名>:<本地分支名>
比如,要取回origin主机的next分支,与本地的master分支合并,需要写成下面这样 -
$ git pull origin next:master
# 相当于:
$ git fetch origin next
$ git merge origin/next
如果远程分支是与当前分支合并,则冒号后面的部分可以省略。
$ git pull origin next
在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone
的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动”追踪”origin/master
分支。
Git也允许手动建立追踪关系。
git branch --set-upstream master origin/next
# 新版本git已经不支持该命令,改为:
git branch --set-upstream-to=origin/master master
上面命令指定master分支追踪origin/next分支。
如果当前分支与远程分支存在追踪关系,git pull就可以省略远程分支名。
$ git pull origin
上面命令表示,本地的当前分支自动与对应的origin主机”追踪分支”(remote-tracking branch)进行合并。
如果当前分支只有一个追踪分支,连远程主机名都可以省略。
$ git pull
上面命令表示,当前分支自动与唯一一个追踪分支进行合并。
如果合并需要采用rebase模式,可以使用–rebase选项。
$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>
如果远程主机删除了某个分支,默认情况下,git pull不会在拉取远程分支的时候,删除对应的本地分支。这是为了防止,由于其他人操作了远程主机,导致git pull不知不觉删除了本地分支。
但是,你可以改变这个行为,加上参数 -p 就会在本地删除远程已经删除的分支。
$ git pull -p
# 等同于下面的命令
$ git fetch --prune origin
$ git fetch -p
$ git fetch <远程主机名>
默认情况下,git fetch取回所有分支(branch)的更新。如果只想取回特定分支的更新,可以指定分支名。
$ git fetch <远程主机名> <分支名>
比如,取回origin主机的master分支。
$ git fetch origin master
所取回的更新,在本地主机上要用”远程主机名/分支名”的形式读取。比如origin主机的master,就要用origin/master读取。
$ git push <远程主机名> <本地分支名>:<远程分支名>
$ git push origin master
上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。
$ git push origin :master
# 等同于
$ git push origin --delete master
上面命令表示删除origin主机的master分支。
如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。
$ git push origin
上面命令表示,将当前分支推送到origin主机的对应分支。
如果当前分支只有一个追踪分支,那么主机名都可以省略。
$ git push
如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
$ git push -u origin master
上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
$ git push --force origin
上面命令使用–force选项,结果导致远程主机上更新的版本被覆盖。
branch management
A successful Git branching model
Understanding the Git Workflow
并不是一定要把本地分支往远程推送:
# 查看分支:
$ git branch -a
# 创建本地分支:
$ git branch <分支名>
# 切换本地分支:
$ git checkout <分支名>
# 创建+切换本地分支:
$ git checkout -b
# 相当于:git branch <分支名> + git checkout <分支名>
# 合并某分支到当前分支:
$ git merge <要合并的分支>
# 将本地分支推送到远程
$ git push origin <要推送的本地分支名>
# 以远程分支为基础,建一个本地分支
$ git checkout -b <本地分支名> origin/<远程分支名>
# 删除本地分支:
$ git branch -d <本地分支名>
# 删除远程分支。将本地空分支推送到远程分支,相当于删除远程分支
$ git push origin :<要删除的远程分支名>
Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标签(git tag -a
),实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG)
来签署或验证。一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。创建一个含附注类型的标签非常简单,用git tag -a
(annotated 的首字母)指定标签名字即可。
注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。
git tag # 列出所有标签
git tag -l 'v1.4.2.*' # 搜索模式
git tag -a v1.4 -m 'my version 1.4'
git show v1.4
后期加注标签:
# 后期加注标签,在提交 “updated rakefile” 后为此项目打上版本号 v1.2
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
$ git tag -a v1.2 9fceb02
默认情况下,git push
并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行 git push origin [tagname]
,比如:
$ git push origin v1.5
如果要一次推送所有本地新增的标签上去,可以使用 --tags 选项:
$ git push origin --tags
git clone
默认会把远程仓库整个给clone下来,但只会在本地默认创建一个master分支,可以使用checkout命令来把远程分支取到本地。
git clone ...
git checkout -b dev origin/dev
# 或者使用-t参数,它默认会在本地建立一个和远程分支名字一样的分支
git checkout -t origin/dev
git branch
git branch -r # 查看远程分支
git branch -a # 查看所有分支
# Git创建Develop分支的命令:
git checkout -b develop master
# 将Develop分支发布到Master分支的命令:
# 切换到Master分支
git checkout master
# 对Develop分支进行合并
git merge --no-ff develop
# 可能需要进行一下分支的关联,指定本地dev分支与远程origin/dev分支的链接:
$ git branch --set-upstream-to=origin/dev dev
当前分支合并到另一分支时,如果没有分歧解决,就会直接移动文件指针。这个过程叫做fast forward
。
举例来说,开发一直在master分支进行,但忽然有一个新的想法,于是新建了一个develop的分支,并在其上进行一系列提交,完成时,回到 master分支,此时,master分支在创建develop分支之后并未产生任何新的commit。此时的合并就叫fast forward
。
Master和Develop是版本库的主要分支。前者用于正式发布,后者用于日常开发。常设分支只需要这两条就够了。
但是,除了常设分支以外,还有一些临时性分支,用于应对一些特定目的的版本开发。临时性分支主要有三种:
# 功能分支的名字,可以采用feature-*的形式命名。
# 创建一个功能分支:
git checkout -b feature-x develop
# 开发完成后,将功能分支合并到develop分支:
git checkout develop
git merge --no-ff feature-x
# 删除feature分支:
git branch -d feature-x
# 创建一个预发布分支:
git checkout -b release-1.2 develop
# 确认没有问题后,合并到master分支:
git checkout maste
git merge --no-ff release-1.2
# 对合并生成的新节点,做一个标签
git tag -a 1.2
# 再合并到develop分支:
git checkout develop
git merge --no-ff release-1.2
# 最后,删除预发布分支:
git branch -d release-1.2
# 创建一个修补bug分支:
git checkout -b fixbug-0.1 master
# 修补结束后,合并到master分支:
git checkout master
git merge --no-ff fixbug-0.1
git tag -a 0.1.1
# 再合并到develop分支:
git checkout develop
git merge --no-ff fixbug-0.1
# 最后,删除"修补bug分支":
git branch -d fixbug-0.1
具体操作时,可能会用到 git stash
1、储藏更改:将当前更改的代码储藏起来,等以后恢复使用
git stash
2、恢复储藏的代码
git stash pop
//恢复的同时把stash内容删掉
或者
git stash apply
//恢复stash,但是stash内容并不删除
git stash drop
//在上面操作的基础上,以此来删除stash
注: git stash list : 查看全部的stash列表。
3、将stash空间清空
git stash clear
4、git stash pop
和 git stash apply
区别
原来git stash pop stash@{id}
命令会在执行后将对应的stash id
从stash list
里删除,而 git stash apply stash@{id}
命令则会继续保存stash id
。
git checkout -b newbranch # create a new branch
# do something...
git add .
git commit -m "do sth"
git checkout master
git merge --no-ff -m "merge new branch" newbranch # merge with no fast forward
git branch -d newbranch
git branch
git push origin master
git push origin dev
# 将本地分支branch1推到远端的branch2:
git push origin branch1:branch2
# 删除分支
git branch -D issues1234 //本地强制删除分支issues1234
git push origin :issues1234 //推到远程
master分支是主分支,因此要时刻与远程同步。
#一些修复bug分支不需要推送到远程去,
#可以先合并到主分支上,然后把主分支master推送到远程去。
#把远程的origin的dev分支到本地来,可使用命令创建本地dev分支:
git checkout –b dev origin/dev
发生冲突的文件
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
其中,git使用 <<<<<<<, =======, >>>>>>>
标记文件中自己和别人产生冲突的部分。
在 <<<<<<<, =======
之间为自己的代码,先出现;
=======, >>>>>>>
之间为别人的代码,后出现。
查看远程库信息,使用`git remote -v`;
修改远程仓库地址`git remote set-url origin new_git_url`
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用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`,如果有冲突,要先处理冲突。
要查看尚未暂存的文件更新了哪些部分,不加参数直接输入git diff
:
$ git diff
此命令比较的是工作目录中当前文件和暂存区域快照之间的差异, 也就是修改之后还没有暂存起来的变化内容。
如果暂存了,用git diff就没有反应了。
若要查看已暂存的将要添加到下次提交里的内容,可以用 git diff --cached
命令。(Git 1.6.1 及更高版本还允许使用 git diff --staged
,效果是相同的,但更好记些。)
总结:
git diff # shows unstaged changes.
git diff --cached # shows staged changes.
git diff HEAD # shows all changes (both staged and unstaged).
版本之间的差异
# 上次提交:HEAD^
git diff HEAD^ HEAD
# As of Git 1.8.5, @ is an alias for HEAD, so you can use:
git diff @~..@
#The following will also work:
git show
# If you want to know the diff between head and any commit you can use:
git diff commit_id HEAD
# And this will launch your visual diff tool (if configured):
git difftool HEAD^ HEAD
# Since comparison to HEAD is default you can omit it (as pointed out by Orient):
git diff @^
git diff HEAD^
git diff commit_id
https://www.cnblogs.com/nicksheng/p/6201711.html
https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97
git cheat sheet
GitHub 漫游指南 – GitHub 漫游指南
git - 简明指南
廖雪峰git
GIT tutorial
GIT PRO BOOK (Chinese)
git tutorial
how to teach git
Follow these simple rules and you’ll become a Git and GitHub master
Git重要概念与常用命令(中文版,速查)
Implementing Git in Data Science
https://www.runoob.com/git/git-basic-operations.html
https://www.w3cschool.cn/git/git-cheat-sheet.html
https://git-scm.com/book/zh/v2