git_to_all

个人仓库管理

初始化操作

因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无知的群众,其次,真的有冒充的也是有办法可查的。

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

新建文件夹并创建为本地git仓库

1
2
3
4
$ mkdir gittest
$ cd gittest\
$ git init
Initialized empty Git repository in I:/gittest/.git/

可见bash提示你创建了一个空的git仓库

修改与提交

创建readme.txt,内容如下

1
2
3
这是一个测试文件

hello git

把文件添加到git仓库暂存区(stage)

1
$ git add readme.txt

git add. :会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件。
git add -u :仅会将被修改的文件提交到暂存区。add -u 不会提交新文件。(git add –update的缩写)
git add -A :是上面两个功能的合集(git add –all的缩写)
提交变更到当前分支并加上说明

1
2
3
4
$ git commit -m "add readme"
[master (root-commit) e5208f9] add readme
1 file changed, 3 insertions(+)
create mode 100644 readme.txt

可见bash提示提交变更到master分支成功

仓库当前的状态

修改reademe.txt内容为如下

1
2
3
4
这是一个测试文件
这是新增的一行
hello git
add a row

使用命令查看仓库状态

1
2
3
4
5
6
7
8
9
10
$ git add readme.txt
$ 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")

git diff file_name可以查看文件具体修改的内容,不过显示的格式是Unix通用的diff格式,看不太清楚
查看提交历史

1
2
3
4
5
6
7
8
9
10
11
12
$ git log                                                        
commit 69f64026b1537fdb1624bd0dd58080e0a40fde7c (HEAD -> master)
Author: Hodge <2991811241@qq.com>
Date: Sun May 6 19:09:09 2018 +0800

第二次提交:新增两行

commit e5208f91bf4f875e22c4fdf6ce53d02169cb1427
Author: Hodge <2991811241@qq.com>
Date: Sun May 6 18:54:06 2018 +0800

add readme

后悔药

查看提交历史精简版

1
2
3
4
$ git log --pretty=oneline
7fdbfe57223ebfce5a34580213d11bd3e988a354 (HEAD -> master) 第三次修改
69f64026b1537fdb1624bd0dd58080e0a40fde7c 第二次提交:新增两行
e5208f91bf4f875e22c4fdf6ce53d02169cb1427 add readme

回退到某一版本git reset --hard 版本id(只写少数几位即可)

1
2
$ git reset --hard 69f6402
HEAD is now at 69f6402 第二次提交:新增两行

此时的readme.txt内容如下

1
2
3
4
这是一个测试文件
这是新增的一行
hello git
add a row

时空穿越成功
可是此时的git log如下

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit 69f64026b1537fdb1624bd0dd58080e0a40fde7c (HEAD -> master)
Author: Hodge <2991811241@qq.com>
Date: Sun May 6 19:09:09 2018 +0800

第二次提交:新增两行

commit e5208f91bf4f875e22c4fdf6ce53d02169cb1427
Author: Hodge <2991811241@qq.com>
Date: Sun May 6 18:54:06 2018 +0800

add readme

第三次提交的记录不见了,看不到commit id如何恢复?

1
2
3
4
5
$ git reflog
69f6402 (HEAD -> master) HEAD@{0}: reset: moving to 69f6402
7fdbfe5 HEAD@{1}: commit: 第三次修改
69f6402 (HEAD -> master) HEAD@{2}: commit: 第二次提交:新增两行
e5208f9 HEAD@{3}: commit (initial): add readme

不能再清晰。

撤销修改

git checkout -- file_name
命令git checkout – readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。

撤销暂存区内容:
Git同样告诉我们,用命令git reset HEAD file_name可以把暂存区的修改撤销掉(unstage),重新放回工作区:

删除文件

Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了
现在你有两个选择:
一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:git checkout -- file_name

远程仓库

第1步:创建SSH Key

1
$ ssh-keygen -t rsa -C "youremail@example.com"

如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。
将公钥添加到github或码云~~~~

在码云创建一个空的仓库命名为learngit
链接远程仓库:

1
$ git remote add origin git@gitee.com:Hodge/learngit.git

第一次推送

1
2
3
4
5
6
7
8
9
10
$ git push -u origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (6/6), 555 bytes | 555.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote: Powered by Gitee.com
To gitee.com:Hodge/learngit.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
从现在起,只要本地作了提交,就可以通过命令

1
$ git push origin master

把本地master分支的最新修改推送至码云,现在,你就拥有了真正的分布式版本库!

分支管理

廖雪峰大神的博客关于分支的动画大赞

实战

首先,我们创建dev分支,然后切换到dev分支

1
2
$ git checkout -b dev
Switched to a new branch 'dev'

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令

1
2
3
$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后,用git branch命令查看当前分支

1
2
3
$ git branch
* dev
master

此时是在dev分支上开发,修改reademe.txt文件内容如下:

1
2
3
4
5
6
这是一个测试文件
这是新增的一行
hello git
add a row

这是在dev分支上的更改

切换回master分支
注意!!此时readme.txt的内容变为:

1
2
3
4
这是一个测试文件
这是新增的一行
hello git
add a row

现在,我们把dev分支的工作成果合并到master分支上

1
2
3
4
5
$ git merge dev
Updating 69f6402..73c4f3f
Fast-forward
readme.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

ok,现在readme.txt内容变为和dev分支一样,此时可以删除dev分支

1
2
$ git branch -d dev
Deleted branch dev (was 73c4f3f).

解决冲突

请看如下操作:
新建dev分支将readme.txt文件改为:

1
text:dev

提交后返回master分支
在master分支将readme.txt文件改为:

1
text:master

提交后试图合并dev分支:

1
2
3
4
$ git merge dev
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

因为在两个分支都对同一文件的同一位置进行了修改,git无法进行自动merge,提示需要手动解决冲突
并且!!!在merge失败后readme.txt内容变成如下:

1
2
3
4
5
<<<<<<< HEAD
text:master
=======
text:dev
>>>>>>> dev

手动修改文件内容为:

1
text:master merge dev

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

1
2
3
4
5
6
7
8
9
$ git log --graph --pretty=oneline --abbrev-commit
* 372f62b (HEAD -> master) 手动merge master and dev
|\
| * 7fc1214 (dev) text:dev
* | bdfdaaf text:master
|/
* 73c4f3f 在dev分支添加一行
* 69f6402 (origin/master) 第二次提交:新增两行
* e5208f9 add readme

分支管理策略

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息
准备合并dev分支,请注意–no-ff参数,表示禁用Fast forward

1
$ git merge --no-ff -m "merge with no-ff" dev

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
合并后,我们用git log看看分支历史

1
2
3
4
5
6
$ git log --graph --pretty=oneline --abbrev-commit
* 7825a50 merge with no-ff
|\
| * 6224937 add merge
|/
* 59bc1cb conflict fixed

Bug分支

当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,
但是,等等,当前正在dev上进行的工作还没有提交

1
2
3
4
5
6
7
8
9
10
11
$ git status
On branch master
Your branch is up-to-date with 'origin/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内容如下:

1
2
3
4
5
6
7
8
9
10
111111
222222
333333
444444
555555
666666
7dev77
888888

dev-------dev

并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作

1
2
$ git stash
Saved working directory and index state WIP on master: 1c1e7ac Merge branch 'dev'

此时

1
2
3
4
5
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working tree clean

readme.txt内容还原为如下:

1
2
3
4
5
6
7
8
111111
master
333333
444444
555555
666666
7dev77
888888

新建bug-1分支,新增bug-1.txt,提交、回答master分支,merge bug-1分支,删除bug-1分支
回到dev分支,工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看

1
2
$ git stash list
stash@{0}: WIP on master: 1c1e7ac Merge branch 'dev'

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了

1
2
3
4
5
6
7
8
9
10
11
$ git stash pop
Auto-merging readme.txt
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: readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (530fcb79063bbcdeac0b414547158ef130bdca7e)

修改、提交、merge、删除分支、推送到远程仓库

Feature分支

添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,
所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
但如果feature分支功能因为某些原因还没merge就需要删除,执行git branch -d 分支名时会
销毁失败。Git友情提醒,feature分支还没有被合并,如果删除,将丢失掉修改,
如果要强行删除,需要使用命令git branch -D 分支名。

多人协作

当多人对同一个远程仓库具有操作权限时:

当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin
多人协作的工作模式通常是这样:

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

这种情况是:你不拥有某仓库的push权限,但你可以Fork别人的项目
Fork后会在你的github上生成一个一样的仓库,你可以将其与自建仓库等同看待。
你在这个仓库上开发,增加了一个很cool的功能,想提交到别人仓库,但是pull request 时可能会出错,因为你fork的repo和现在的别人的repo已经不一样了,
因为别人也在开发并push啊。所以你要pull别人仓库最新的代码,然后手动merge冲突,然后再pull request并祈祷别人接受你的pull

标签管理

tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
命令git tag <name>就可以打一个新标签,git tag查看所有标签。
默认标签是打在最新提交的commit上的。对于以前提交的commit想要增加标签只需在添加标签语句后面添加commit id即可。
可以用git show <tagname>查看标签信息。
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:

1
git tag -a v0.1 -m "version 0.1 released" 3628164

git tag -d v0.1删除标签
将标签推送到远程:
单个推送:git push origin v1.0
全部推送git push origin --tags
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除、然后,从远程删除。删除命令也是push,但是格式如下:
git push origin :refs/tags/<tagname>

自定义Git

.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理
https://github.com/github/gitignore
强制添加:git add -f App.class
或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore -v <filename>命令检查。