Git
Git分为了工作区,版本区,远程仓库区。
本地仓库是对于远程仓库而言的。本地仓库 = 工作区 + 版本区。
工作区即磁盘上的文件集合。
版本区(版本库)即.git文件。
版本库 = 暂存区(stage) + 分支(master) + 指针Head。
HEAD commit版本,严格来说是指向当前分支
操作流程
如果没有加入团队,那么就fork仓库,自己改好后,如果觉得自己改的比较好,想要原版也拥有,可以向原版发生pull请求,原版觉得ok就会同意pull,并pull到原版的仓库中,这样就算是参与到了版主的项目建设了 (不过一般都是直接fork下来,白嫖吧)。
分支原理
创建新的分支,例如dev
时,Git
新建了一个指针叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上
bash基本命令
cd
切换
pwd
显示当前目录路径
ls
列出所有文件
touch
新建文件
rm
删除文件
mkdir
新建文件夹
rm -r
删除文件夹
mv filename path
移动文件
reset /clear
清屏
exit
退出bash
git config
要提交git项目,首先要告诉git你是谁,否则只能拉取项目,而不能修改项目。
git config --global user.name EdwardGit
git config --global user.emil pocketknifegithub@163.com
global表示全局,这台机器所有的Git仓库都会使用这个配置。允许单个仓库使用其他的名字和邮箱。
git config -l
/–list查看global配置信息
git config -e
打开该项目所属的配置文件
git config -e --global
打开该主机的全局配置文件
git config -e --system
打开配置所有主机所有项目的配置文件
打开git终端,或者idea中的插件终端,输入命令:
git config --global credential.helper store
只要输入一次密码。后面就不用在输入了
git init
在本地新建一个repo,进入一个项目目录,执行git init,会初始化一个repo,并在当前文件夹下创建一个.git文件夹.
git克隆
-
在需要clone的文件夹处右键,点击git bash here 进入控制面板,输入命令
git init
初始化文件夹,将文件夹变成git可管理的仓库 -
继续输入命令,
git clone 仓库地址
点击回车,自动下载项目
git status
- 查询repo的状态,可以查看repo中所有的文件名。
- git status -s: -s表示short, -s的输出标记会有两列,第一列是对staging区域而言,第二列是对working目录而言.
git log
- show commit history of a branch,可以查看提交的历史日志
git log --oneline --number
: 每条log只显示一行,显示number条.git log --oneline --graph
:可以图形化地表示出分支合并历史.git log branchname
可以显示特定分支的log.git log --oneline branch1 ^branch2
,可以查看在分支1,却不在分支2中的提交.表示排除这个分支(Window下可能要给branch2加上引号).git log --decorate
会显示出tag信息.git log --author=[author name]
可以指定作者的提交历史.git log --since --before --until --after
根据提交时间筛选log.--no-merges
可以将merge的commits排除在外.- git log --grep 根据commit信息过滤log:
git log --grep=keywords
- 默认情况下, git log --grep --author是OR的关系,即满足一条即被返回,如果你想让它们是AND的关系,可以加上–all-match的option.
- git log -S: filter by introduced diff.
- 比如: git log -SmethodName (注意S和后面的词之间没有等号分隔).
- git log -p: show patch introduced at each commit.
- 每一个提交都是一个快照(snapshot),Git会把每次提交的diff计算出来,作为一个patch显示给你看.
- 另一种方法是git show [SHA].
- git log --stat: show diffstat of changes introduced at each commit.
- 同样是用来看改动的相对信息的,–stat比-p的输出更简单一些.
git add
- 在提交之前,Git有一个暂存区(staging area),可以放入新添加的文件或者加入新的改动. commit时提交的改动是上一次加入到staging area中的改动,而不是我们disk上的改动.
git add .
会递归地添加当前工作目录中的所有文件,即把工作区的所有文全部提交到版本区里面的暂存区
git diff
-
git diff
:show diff of unstaged changes.此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容.
-
git diff --cached
show diff of staged changes.若要看已经暂存起来的文件和上次提交时的快照之间的差异,可以用 -
(Git 1.6.1 及更高版本还允许使用 git diff --staged,效果是相同的).
-
git diff HEAD
show diff of all staged or unstated changes. -
也即比较woking directory和上次提交之间所有的改动.
-
如果想看自从某个版本之后都改动了什么,可以用:
-
git diff [version tag]
-
跟log命令一样,diff也可以加上–stat参数来简化输出.
-
git diff [branchA] [branchB]可以用来比较两个分支.
-
它实际上会返回一个由A到B的patch,不是我们想要的结果.
-
一般我们想要的结果是两个分支分开以后各自的改动都是什么,是由命令:
-
git diff [branchA]…[branchB]给出的.
-
实际上它是:git diff $(git merge-base [branchA] [branchB]) [branchB]的结果.
git commit
- 提交已经被add进来的改动.
- git commit -m “the commit message" 把暂存区的所有文件提交到仓库区,并备注
- git commit -a 会先把所有已经track的文件的改动add进来,然后提交(有点像svn的一次提交,不用先暂存). 对于没有track的文件,还是需要git add一下.
- git commit --amend 增补提交. 会使用与当前提交节点相同的父节点进行一次新的提交,旧的提交将会被取消.
git reset
- undo changes and commits.
- git reset HEAD:
- unstage files from index and reset pointer to HEAD
- 这里的HEAD关键字指的是当前分支最末梢最新的一个提交.也就是版本库中该分支上的最新版本.
- 这个命令用来把不小心add进去的文件从staged状态取出来,可以单独针对某一个文件操作: git reset HEAD - - filename, 这个- - 也可以不加.
- git reset --soft
- move HEAD to specific commit reference, index and staging are untouched.
- git reset --hard
- unstage files AND undo any changes in the working directory since last commit.
- 使用git reset --hard HEAD进行reset,即上次提交之后,所有staged的改动和工作目录的改动都会消失,还原到上次提交的状态.
- 这里的HEAD可以被写成任何一次提交的SHA-1.
- 不带soft和hard参数的git reset,实际上带的是默认参数mixed.
- 总结:
- git reset --mixed id,是将git的HEAD变了(也就是提交记录变了),但文件并没有改变,(也就是working tree并没有改变). 取消了commit和add的内容.
- git reset --soft id. 实际上,是git reset –mixed id 后,又做了一次git add.即取消了commit的内容.
- git reset --hard id.是将git的HEAD变了,文件也变了.
- 按改动范围排序如下:
- soft (commit) < mixed (commit + add) < hard (commit + add + local working)
git revert
- 反转撤销提交.只要把出错的提交(commit)的名字(reference)作为参数传给命令就可以了.
git revert HEAD
: 撤销最近的一个提交.- git revert会创建一个反向的新提交,可以通过参数-n来告诉Git先不要提交.
git rm
- git rm file: 从staging区移除文件,同时也移除出工作目录.
- git rm --cached: 从staging区移除文件,但留在工作目录中.
- git rm --cached从功能上等同于git reset HEAD,清除了缓存区,但不动工作目录树.
git clean
- git clean是从工作目录中移除没有track的文件.
- 通常的参数是git clean -df:
- -d表示同时移除目录,-f表示force,因为在git的配置文件中, clean.requireForce=true,如果不加-f,clean将会拒绝执行.
git mv
- git rm - - cached orig; mv orig new; git add new
git stash
- 把当前的改动压入一个栈.将你修改后的代码存储到本地(一个栈结构)–>一般会在git pull 拉取代码失败时使用
- git stash将会把当前目录和index中的所有改动(但不包括未track的文件)压入一个栈,然后留给你一个clean的工作状态,即处于上一次最新提交处.
- git stash list会显示这个栈的list.
- git stash apply:取出stash中的上一个项目(stash@{0}),并且应用于当前的工作目录.
- 也可以指定别的项目,比如git stash apply stash@{1}.
- 如果你在应用stash中项目的同时想要删除它,可以用(将你stash到本地的代码与重新git pull下的代码合并)git stash pop
- 删除stash中的项目:
- git stash drop: 删除上一个,也可指定参数删除指定的一个项目.
- git stash clear: 删除所有项目.
git branch
git branch -v
可以看见每一个分支的最后一次提交.git branch
: 列出本地所有分支,当前分支会被星号标示出.git branch (branchname)
: 创建一个新的分支(当你用这种方式创建分支的时候,分支是基于你的上一次提交建立的).git branch -d (branchname)
: 删除一个分支.- 删除remote的分支:
- git push (remote-name):(branch-name): delete a remote branch.
- 这个是因为完整的命令形式是:
- git push remote-name local-branch:remote-branch
- 而这里local-branch的部分为空,就意味着删除了remote-branch
git checkout
git checkout (branchname)
:切换到一个分支.git checkout -b (branchname)
: 创建并切换到新的分支.这个命令是将git branch newbranch和git checkout newbranch合在一起的结果.- checkout还有另一个作用:替换本地改动:
- git checkout –
- 此命令会使用HEAD中的最新内容替换掉你的工作目录中的文件.已添加到暂存区的改动以及新文件都不会受到影响.
- 注意:git checkout filename会删除该文件中所有没有暂存和提交的改动,这个操作是不可逆的.
git merge
- 把一个分支merge进当前的分支.
- git merge [alias]/[branch]
- 把远程分支merge到当前分支.
- 如果出现冲突,需要手动修改,可以用git mergetool.
- 解决冲突的时候可以用到git diff,解决完之后用git add添加,即表示冲突已经被resolved.
git tag
- tag a point in history as import.
- 会在一个提交上建立永久性的书签,通常是发布一个release版本或者ship了什么东西之后加tag.
- 比如: git tag v1.0
- git tag -a v1.0, -a参数会允许你添加一些信息,即make an annotated tag.
- 当你运行git tag -a命令的时候,Git会打开一个编辑器让你输入tag信息.
- 我们可以利用commit SHA来给一个过去的提交打tag:
- git tag -a v0.9 XXXX
- push的时候是不包含tag的,如果想包含,可以在push时加上–tags参数.
- fetch的时候,branch HEAD可以reach的tags是自动被fetch下来的, tags that aren’t reachable from branch heads will be skipped.如果想确保所有的tags都被包含进来,需要加上–tags选项.
git remote
- list, add and delete remote repository aliases.
- 因为不需要每次都用完整的url,所以Git为每一个remote repo的url都建立一个别名,然后用git remote来管理这个list.
git remote add origin Git_Repo_URL
把本地仓库与远程仓库连接起来。- git remote: 列出remote aliases.
- 如果你clone一个project,Git会自动将原来的url添加进来,别名就叫做:origin.
git remote -v
:可以看见每一个别名对应的实际url.- git remote add [alias] [url]: 添加一个新的remote repo.
- git remote rm [alias]: 删除一个存在的remote alias.
- git remote rename [old-alias] [new-alias]: 重命名.
- git remote set-url [alias] [url]:更新url. 可以加上—push和fetch参数,为同一个别名set不同的存取地址.
git fetch
- download new branches and data from a remote repository.
- 可以
git fetch [alias]
取某一个远程repo,也可以git fetch --all
取到全部repo - fetch将会取到所有你本地没有的数据,所有取下来的分支可以被叫做remote branches,它们和本地分支一样(可以看diff,log等,也可以merge到其他分支),但是Git不允许你checkout到它们. 在本地主机上要用"远程主机名/分支名"的形式读取。比如origin主机的master,就要用origin/master读取;
git pull
- fetch from a remote repo and try to merge into the current branch.
- pull == fetch + merge FETCH_HEAD
- git pull会首先执行git fetch,然后执行git merge,把取来的分支的head merge到当前分支.这个merge操作会产生一个新的commit.
- 如果使用–rebase参数,它会执行git rebase来取代原来的git merge.
git rebase
- -
-rebase
不会产生合并的提交,它会将本地的所有提交临时保存为补丁(patch),放在”.git/rebase”目录中,然后将当前分支更新到最新的分支,最后把保存的补丁应用到分支上。本地的所有提交记录会被丢弃。 - rebase的过程中,也许会出现冲突,Git会停止rebase并让你解决冲突,在解决完冲突之后,用git add去更新这些内容,然后无需执行commit,只需要:
git rebase --continue
就会继续打余下的补丁.git rebase --abort
将会终止rebase,当前分支将会回到rebase之前的状态.
git push
- push your new branches and data to a remote repository.
- git push [alias] [branch]
- git push -u origin master 把仓库区的文件提交到远程仓库里。
- 将会把当前分支merge到alias上的[branch]分支.如果分支已经存在,将会更新,如果不存在,将会添加这个分支.
- 如果有多个人向同一个remote repo push代码, Git会首先在你试图push的分支上运行git log,检查它的历史中是否能看到server上的branch现在的tip,如果本地历史中不能看到server的tip,说明本地的代码不是最新的,Git会拒绝你的push,让你先fetch,merge,之后再push,这样就保证了所有人的改动都会被考虑进来.
git reflog
- git reflog是对reflog进行管理的命令,reflog是git用来记录引用变化的一种机制,比如记录分支的变化或者是HEAD引用的变化.
- 当git reflog不指定引用的时候,默认列出HEAD的reflog.
- HEAD@{0}代表HEAD当前的值,HEAD@{3}代表HEAD在3次变化之前的值.
- git会将变化记录到HEAD对应的reflog文件中,其路径为.git/logs/HEAD, 分支的reflog文件都放在.git/logs/refs目录下的子目录中.
版本的回溯与前进
提交一个文件,有时候我们会提交很多次,在提交历史中,这样就产生了不同的版本。每次提交,Git会把他们串成一条时间线。如何回溯到我们提交的上一个版本,用git reset --hard + 版本号即可。版本号可以用git log来查看,每一次的版本都会产生不一样的版本号。
回溯之后,git log查看一下发现离我们最近的那个版本已经不见了。但是我还想要前进到最近的版本应该如何?只要git reset --hard + 版本号就行。退一步来讲,虽然我们可以通过git reset --hard + 版本号,靠记住版本号来可以在不同的版本之间来回穿梭。
但是,有时候把版本号弄丢了怎么办?git reflog帮你记录了每一次的命令,这样就可以找到版本号了,这样你又可以通过git reset来版本穿梭了。
撤销
场景1:在工作区时,你修改了一个东西,你想撤销修改,git checkout – file。廖雪峰老师指出撤销修改就回到和版本库一模一样的状态,即用版本库里的版本替换工作区的版本。
场景2:你修改了一个内容,并且已经git add到暂存区了。想撤销怎么办?回溯版本,git reset --hard + 版本号,再git checkout – file,替换工作区的版本。
场景3:你修改了一个内容,并且已经git commit到了master。跟场景2一样,版本回溯,再进行撤销。
删除
如果你git add一个文件到暂存区,然后在工作区又把文件删除了,Git会知道你删除了文件。如果你要把版本库里的文件删除,git rm 并且git commit -m “xxx”.
如果你误删了工作区的文件,怎么办?使用撤销命令,git checkout --就可以。这再次证明了撤销命令其实就是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
ssh与https协议
使用git进行版本控制时,可以选择使用https或者ssh协议来进行项目的push和poll
为什么要配置公钥和私钥:
Git使用https协议,每次pull, push都要输入密码,相当的烦。 使用ssh协议,然后使用ssh密钥。这样可以省去每次都输密码。
公钥我们一般是给服务器的,他们到时候在权限中加入我给的公钥,然后当我从远地仓库中下载项目的时候,我在git clone xxx
的时候,那个服务器我通过他的绑定的公钥来匹配我的私钥,这个时候,如果匹配,则就可以正常下载,如果不匹配,则失败.
大多数 Git 服务器都会选择使用 SSH 公钥来进行授权。系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。
配置步骤
查看公钥
cd ~/.ssh
创建公钥(重新创建也是一样,中间一直enter就行了,不用设置密码)
ssh-keygen -t ras -C 'emailAdress'
创建后,在.ssh目录里有两个文件,分别为id_rsa(私钥),id_rsa.pub(公钥),
然后把公钥加到github/gitlab上的ssh keys设置上即可
ls -al ~/.ssh
查看.ssh文件下是否已经成功创建了id_rsa(私钥),id_rsa.pub(公钥),这两个文件
ssh-agent bash
ssh-add ~/.ssh/id_rsa
把专用密钥添加到ssh-agent的高速缓存中,配置私钥,配置后,在连接ssh是就不用输入密码了。
ssh -T git@github.com
查看密钥对是否可以使用
工作
连接远程仓库
- git init
- git remote add origin repoAddress
- git remote -v
- git pull --rebase origin master
- git fecth
- 修改文件
- git add .
- git commit -m “提示信息”
- git push origin master
添加origin的时候,可以改成其他的名字。origin是git默认的叫法
如果使用–rebase参数,它会执行git rebase来取代原来的git merge.不会产生合并的提交,它会将本地的所有提交临时保存为补丁(patch),放在”.git/rebase”目录中,然后将当前分支更新到最新的分支,最后把保存的补丁应用到分支上。本地的所有提交记录会被丢弃。
git push -u origin master -f
如果远程库是空的,我们第一次推送master
分支时,加上了-u参数,Git不但会把本地的master
分支内容推送的远程新的master
分支,还会把本地的master
分支和远程的master
分支关联起来,在以后的推送或者拉取时就可以简化命令。如果是新的仓库,仓库中只有一个readme.md文件, 但是没有文件夹的话。那么git push origin master 的时候,会报everything up-to-date,所有在read里修改的内容,都不会被上传到remote。只有新建一个文件夹,并在里面添加一个文件,再执行提交才能够成功push
创建,并提交到分支
- git branch 分支名字
- git checkout branchName
- git branch
- git add .
- git commit -m “message”
- git push origin branchName
git branch -b branchName
命令加上-b
参数表示创建并切换
git brach -d branchName
表示删除分支使用
git push -u origin branchName
后,第二次push可以直接使用git push
如何建项目实现多人协作
https://www.cnblogs.com/zhaoyanjun/p/5882784.html
解决冲突
在分支上提交一个修改,转到master后又提交一个修改,两个修改都在同一个位置,请问如何合并?
git无法快速合并,只能试图把各自修改合并起来
git merge dev 后,部分合并,但有部分没有合并有冲突,需要手动合并
- git status 查看状态
- 手动修改conflicts
- git commit -m “”
通过命令
git log --graph --pretty=oneline --abbrev-commit
查看分支情况
分支管理策略
master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;- 干活都在
dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本 - 你和你的小伙伴们每个人都在
dev
分支上干活,每个人都有自己的分支,时不时地往dev
分支上合并就可以了。 - 使用
git merge --no-ff -m "merge with no-ff" dev
合并会留下历史信息
Bug分支
正在写的分支,以及需要重新创建新的分支去修复bug
-
git stash 把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
-
git checkout master
-
git checkout -b bugBranch
-
修改完成
-
git commit -m “fix bug”
-
git checkout master
-
git merge --no-ff -m “merged bug” bugBranch
-
git chekout myBranch
-
git status 查看状态
-
git stash pop 恢复的同时把stash内容也删了
或者
git stash apply 恢复后,
stash
内容并不删除git satsh drop 删除stash内容
git pull 不成功
git监控的单位是文件,,也就是说假如其他开发者改动了XXX文件,并且同步到远程库了,你即使在XXX文件里改动了一个标点,加了一个空格,都无法pull成功.
git pull不成功时,需要使用git stash命令
- git stash 将刚开发完的代码存储到本地
- git checkout master
- git pull 拉取远程仓库的代码
- git stash pop 将stash后的代码取出并与刚pull下单代码进行合并,解决同一文件下的冲突
- git add .
- git commit -m “message”
- git push origin branchName
merge的使用
https://blog.csdn.net/nrsc272420199/article/details/85227095
代码合并
先切换回自己的master分支
git fetch
or git fetch origin master:temp
在本地新建一个temp分支,并将远程origin仓库的master分支代码下载到本地temp分支;
- git diff temp 比较本地代码与刚刚从远程下载下来的代码的区别;
- git merge temp 合并temp分支到本地的master分支;
- git branch -d temp 如果不想保留temp分支,删除;
与git pull相比git fetch相当于是从远程获取最新版本到本地,但不会自动merge。如果需要有选择的合并git fetch是更好的选择。效果相同时git pull将更为快捷;