git命令

安装git:

yum install zlib (系统默认已经装上)
yum install zlib-devel 
sudo yum install gcc-c++
yum install perl-ExtUtils-CBuilder perl-ExtUtils-MakeMaker
wget https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz
tar -zxvf git-2.10.0.tar.gz
cd git-2.10.0
./configure
make
make install

git config --global user.name "Your Name"
git config --global user.email "email@example.com"

创建版本库:

mkdir learngit
git init    //通过git init命令把这个目录变成Git可以管理的仓库,当前目录下多了一个.git的目录,用ls -ah命令就可以看见。
touch readme.txt    //新建一个文件
git add readme.txt    //把文件添加到仓库
git commit -m "wrote a readme file"    //把文件提交到仓库

因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

git add file1.txt
git add file2.txt file3.txt
git commit -m "add 3 files."

git status命令可以让我们时刻掌握仓库当前的状态。
git diff命令查看上次修改的内容。此命令比较的是工作目录中当前文件和暂存区域快照之间的差异, 也就是修改之后还没有暂存起来的变化内容。
git diff --staged命令查看已暂存的将要添加到下次提交里的内容。
git commit -a命令Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而可以跳过 git add 步骤。
git rm filename命令删除暂存区中的文件。
git rm --cached filename命令删除暂存和已经提交的文件。
git mv file_from file_to命令重命名文件,相当于$ mv README.md README,$ git rm README.md,$ git add README三个命令。
git log命令查看提交历史记录。回退后记录被清除。也可加上--pretty=oneline参数:git log --pretty=oneline
git reflog命令查看命令历史记录。

版本回退:
Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交(例如:3628164...882e1e0),上一个版本就是HEAD^, 上上一个版本就是HEAD^^, 往上100写成HEAD~100。

git reset --hard HEAD^
git reset --hard 3628164    //版本号前几位即可
  • soft 参数:将本地版本库的头指针全部重置到指定版本,且将这次提交之后的所有变更都移动到暂存区。
  • 默认的mixed参数:将本地版本库的头指针全部重置到指定版本,且会重置暂存区,即这次提交之后的所有变更都移动到未暂存阶段(工作区)。
  • hard参数:会将工作区代码也回退到这个版本

工作区和暂存区:
比如learngit文件夹就是一个工作区,工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。



如上图
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
在创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

管理修改:
第一次修改 -> git add -> 第二次修改 -> git commit
Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交。在工作区的第二次修改并没有放入暂存区,所以git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。

撤销修改:

git checkout -- readme.txt

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:

  • readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
  • readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
    总之,就是让这个文件回到最近一次git commit或git add时的状态。
git reset HEAD readme.txt

用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage)。

场景1:当修该了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
场景2:当修改了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退,不过前提是没有推送到远程库。

删除文件:

rm test.txt
git status    //这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了
git rm test.txt
git commit -m "remove test.txt"

rm test.txt
git status
git checkout -- test.txt    //撤销了删除操作,其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

GitHub:

生成ssh

https://github.com/settings/ssh 中添加公钥。

git remote add origin git@github.com:zzhblh/HelloWorld.git    //远程库的名字就是origin,这是Git默认的叫法
git push -u origin master

第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
更好的方式是先创建远程库,然后,从远程库克隆:

git clone git@github.com:zzhblh/HelloWorld.git

会在当前目录创建一个叫做HelloWorld的git目录。

分支管理:
一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:


当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
git checkout -b dev git checkout命令加上-b参数表示创建并切换,相当于git branch dev git checkout dev。查看当前分支git branch,当前分支前面会标一个*号。

从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
如果git checkout master切换回master,会发现master没有改变,因为那个提交是在dev分支。

假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
git checkout master切换回master,git merge dev命令用于合并指定分支到当前分支。直接把master指向dev的当前提交。

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

解决冲突:


这种情况下,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.

git status可以告诉我们冲突的文件:

git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

我们可以直接查看readme.txt的内容:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1

Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:

Creating a new branch is quick and simple.

再提交:

git add readme.txt 
git commit -m "conflict fixed"
[master 59bc1cb] conflict fixed

现在,master分支和feature1分支变成了下图所示:



用带参数的git log也可以看到分支的合并情况:

git log --graph --pretty=oneline --abbrev-commit
*   59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...

最后,删除feature1分支:

git branch -d feature1
Deleted branch feature1 (was 75a857c)

分支策略:
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活。
干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本。
每个人都在dev分支上干活,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:

Bug分支:
Git还提供了一个stash功能,需要把当前工作现场“储藏”起来,等以后恢复现场后继续工作。需要stash的原因是因为一个本地的git repo只有一个工作区和暂存区,而我们的checkout只是将HEAD指针从一个分支切换到另一个分支。所以工作区或暂存区不‘干净’(有未commit或stash的内容)的话,会把当前的修改提交到切换之后的分支。
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
$ git checkout -b issue-101
Switched to a new branch 'issue-101'

现在修复bug,需要把“Git is free software ...”改为“Git is a free software ...”,然后提交:

$ git add readme.txt 
$ git commit -m "fix bug 101"
[issue-101 cc17032] fix bug 101
 1 file changed, 1 insertion(+), 1 deletion(-)

修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
 readme.txt |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-101
Deleted branch issue-101 (was cc17032).

现在,是时候接着回到dev分支干活了。为了保证dev上的相同bug被修复,需要将master合并至dev上:checkout dev切换回dev分支,git merge master合并master至dev上。

$ git checkout dev
Switched to branch 'dev'
$ git merge master
$ git status
# On branch dev
nothing to commit (working directory clean)

工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:

$ git stash list
stash@{0}: WIP on dev: 6224937 add merge

工作区需要恢复,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了。
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

$ git stash apply stash@{0}

推送/抓取分支:
多人协作时,大家都会往master和dev分支上推送各自的修改。当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote:

$ git remote
origin

或者,用git remote -v显示更详细的信息:

$ git remote -v
origin  git@github.com:zzhblh/HelloWorld.git (fetch)
origin  git@github.com:zzhblh/HelloWorld.git (push)

上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

推送分支:
就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:

$ git push origin master

如果要推送本地dev分支到远程dev分支,就改成:

$ git push origin dev:dev

抓取分支:
从远程库clone时,默认情况下,只能看到本地的master分支。可以用git branch命令查看:

$ git branch
* master

git fetch:相当于是从远程获取最新版本到本地,不会自动merge。
从远程的origin的master分支到origin/master分支上:

    Git fetch origin master

从远程获取origin的remotebranch分支到本地,本地会创建一个remotebranch的copy:

    $git checkout localbranch
    $git fetch origin remotebranch
    $git branch
    master
    *localbranch
    remotebranch

从远程获取master到本地的tmp分支上(不会自动切换到该分支),之后再进行比较合并:

    git fetch origin master:tmp
    git diff tmp 
    git merge tmp

git pull:相当于是从远程获取最新版本并merge到本地,其实相当于git fetch 和 git merge。
从远程的origin的master主分支下载最新的版本,并与当前分支进行合并:

    git pull origin master

在实际使用中,git fetch更安全一些。因为在merge前,我们可以查看更新情况,然后再决定是否合并。

跟踪远程分支:从远程分支 checkout 出来的本地分支,称为跟踪分支 (tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git push/ git pull,Git 会自行推断应该向哪个服务器的哪个分支推送/获取数据。在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master。这正是 git push 和 git pull 一开始就能正常工作的原因。

$ git checkout -b dev origin/dev

或关联本地已存在的dev分支:

$ git branch --set-upstream dev origin/dev

多人协作的工作模式通常是这样:
首先,可以试图用git push origin branch-name推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name

git仓库:
安装git后,创建一个git用户组和用户,用来运行git服务:

$ groupadd git
$ adduser git -g git

创建证书登录
收集所有需要登录的用户的公钥,客户端的公钥在客户端的id_rsa.pub文件中,把我们的公钥导入到刚创建的用户git下的.ssh目录(没有.ssh目录则创建)。/home/git/.ssh/authorized_keys文件里,一行一个。
如果没有该文件创建它:

$ cd /home/git/
$ mkdir .ssh
$ chmod 700 .ssh
$ touch .ssh/authorized_keys
$ chmod 600 .ssh/authorized_keys

初始化Git仓库
首先我们选定一个目录作为Git仓库,假定是/home/gitrepo/w3cschoolcc.git,在/home/gitrepo目录下输入命令:

$ cd /home
$ mkdir gitrepo
$ chown -R git:git gitrepo/
$ cd gitrepo
//创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾
$ git init --bare w3cschoolcc.git
Initialized empty Git repository in /home/gitrepo/w3cschoolcc.git/

以上命令Git创建一个空仓库,服务器上的Git仓库通常都以.git结尾。然后,把仓库所属用户改为git:

$ chown -R git:git w3cschoolcc.git

在其他机器上就可以克隆仓库

$ git clone git@192.168.45.4:/home/gitrepo/w3cschoolcc.git
Cloning into 'w3cschoolcc'...
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

在IntelliJ IDEA中使用仓库
设置git.exe路径:


重启idea,在vcs下可以看到git菜单项。

把一个本地项目提交到刚刚创建的git仓库:

  • vcs->Import into Version Control->Create Git Repository选中目录,把它变成git目录。
  • vcs->git->remotes关联远程库,URL为仓库地址git@192.168.45.4:/home/gitrepo/w3cschoolcc.git。
  • vcs->git->push即可推送。
  • vcs->git->branch -> +New Branch,输入分支名称,自动创建并切换到新的分支。
  • vcs->git->branch->分支名->Checkout切换分支。

从仓库获取项目:

  • vcs->Check Out from Version Control->Git。
  • 填写仓库地址和本地目录名字。



参考:
https://git-scm.com/book/zh/v1/
https://marklodato.github.io/visual-git-guide/index-zh-cn.html
https://segmentfault.com/q/1010000000156026

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,348评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,122评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,936评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,427评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,467评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,785评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,931评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,696评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,141评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,483评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,625评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,291评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,892评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,492评论 2 348

推荐阅读更多精彩内容