Haste makes waste

Git教程(廖雪峰)

Posted on By lijun

感谢廖老师出品Git教程,浅显易懂。

0. 总结

  1. 初始化一个Git仓库:git init
  2. 添加文件到Git仓库step1:git add <file>
  3. 添加文件到Git仓库step2:git commit -m <message>
  4. 要随时掌握工作区的状态,使用:git status
  5. 如果git status告诉你有文件被修改过,用:git diff查看修改内容
  6. HEAD指向的版本就是当前版本,因此可以在各个版本之间穿梭,git reset --hard eb69 (回到eb69版本),或git reset --hard HEAD^ (回退到前一个版本)
  7. 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本,或是简介版git log --pretty=oneline
  8. 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本
  9. 查看当前仓库版本,与工作区版本的差别:git diff HEAD -- readme.txt
  10. 丢弃工作区的修改时,用命令: git checkout -- readme.txt
  11. 丢弃暂存区的修改,用命令:git reset HEAD readme.txt
  12. 删除暂存区的文件,git rm,与git add一样地位的命令,然后git commit提交到仓库
  13. 本地创建SSH Key,ssh-keygen -t rsa -C "lijun.kawasaki@gmail.com"
  14. 要关联一个远程库,使用命令:git remote add origin https://github.com/utanesuke0612/learngit.git
  15. 关联后,使用命令:git push -u origin master第一次推送master分支的所有内容
  16. 每次本地提交后,使用:git push origin master推送最新修改
  17. 用命令git clone https://github.com/utanesuke0612/udacitystudy.git克隆一个远程库到本地
  18. 查看分支:git branch
  19. 创建分支:git branch <name>
  20. 切换分支:git checkout <name>
  21. 创建+切换分支:git checkout -b <name>
  22. 合并某分支到当前分支:git merge <name>`
  23. 删除分支:git branch -d <name>
  24. 如果两个不同分支上,针对同一个文件进行了修改,在合并分支的时候,可能会出现合并冲突,这时候要手动解决冲突,然后再添加并提交。
  25. 通过git log --graph命令可以看到分支合并图。
  26. 通过这种方式merge,能够保留分支上的信息,git merge --no-ff -m "merge with no-ff" dev
  27. 通过 git log --graph --pretty=oneline --abbrev-commit 查看分支历史
  28. 当手头工作没有完成时,先把工作现场git stash 一下,然后去修复bug,修复后,再 git stash pop ,回到工作现场。
  29. 开发一个新feature,最好新建一个分支
  30. 如果要丢弃一个没有被合并过的分支,可以通过git branch -D 强行删除
  31. 查看远程信息用git remote,更详细信息用git remote -v
  32. 创建远程origin的dev分支到本地:git checkout -b dev origin/dev
  33. git push origin dev推送自己的修改
  34. 如果推送失败,是因为远程分支比本地版本更新,需要使用git pull更新到本地
  35. 如果更新到本地时有冲突,则解决冲突后再add-commit-push
  36. 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream dev origin/dev
  37. 敲命令git tag <name>就可以打一个新标签,默认标签是打在最新提交的commit上
  38. 通过后面的commitidgit tag v0.9 5508,可以将变迁打在历史版本上
  39. 通过-m可以给标签添加信息:git tag -a v0.8 -m "ver0.8 released" ca3e
  40. 命令git tag可以查看所有标签。
  41. 显示指定标签git show v0.8
  42. 命令git push origin v1.0可以推送一个本地标签
  43. 命令git push origin --tags可以推送全部未推送过的本地标签
  44. 命令git tag -d v0.9可以删除一个本地标签
  45. 命令git push origin :refs/tags/v0.9可以删除一个远程标签
  46. 忽略某些文件时,需要编写.gitignore
  47. 强制添加文件到仓库git add -f Desktop.ini
  48. 查看是哪条ignore命令限定了指定文件:git check-ignore -v Desktop.ini
  49. 可以通过git config --global alias.st status配置命令的别名,添加–global表示针对用户有效,不加是针对仓库有效
  50. 通过Ubuntu可以很简单的搭建自己的git服务器,具体步骤参考[6.3 搭建Git服务器]

0. 小结(cheetsheet)

image image

1. Git简介

image

1. 安装Git

Linux:

使用$ gitsudo apt-get install git(Ubuntu),

另外,MAC上通过XCode直接安装。

Windows:

直接官网下载安装,菜单中有 Git->Git Bash说明安装成功。

安装完成后,还需要最后一步设置,在命令行输入:

$ git config --global user.name "utane"
$ git config --global user.email "lijun.kawasaki@gmail.com"

注意git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置。

2. 创建版本库

这个目录里面所有文件都可以被Git管理,修改删除等都能跟踪,以便任何时候都能追踪历史和还原。

  • 选择合适位置创建空目录:
utane@ubuntu:~$ mkdir learngit
utane@ubuntu:~$ cd learngit/
utane@ubuntu:~/learngit$ pwd
/home/utane/learngit
  • 通过git init命令把这个目录变成Git可以管理的仓库:
utane@ubuntu:~/learngit$ git init
Initialized empty Git repository in /home/utane/learngit/.git/

通过下面的命令,可以看到创建了对应的目录,.git这个目录是Git来跟踪管理版本库的。

utane@ubuntu:~/learngit$ ls -ah
.  ..  .git
  • 对应目录下添加文件
utane@ubuntu:~/learngit$ vim readme.txt

新建一个文件readme.txt并写入如下内容:

Git is a version control system.
Git is free software.
  • step1:将文件添加到仓库git add
utane@ubuntu:~/learngit$ git add readme.txt
  • step2:把文件提交到仓库git commit
utane@ubuntu:~/learngit$ git commit -m "wrote a readme file"
[master (root-commit) 4568339] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt
utane@ubuntu:~/learngit$ 

2. 时光穿梭

现在我们来修改刚才的文件,添加一行:

Git is a version control system.
Git is free software.

add more @1st

运行git status可以查看仓库的当前状态:

utane@ubuntu:~/learngit$ git status
ブランチ 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这个命令看看修改的内容:

utane@ubuntu:~/learngit$ git diff
diff --git a/readme.txt b/readme.txt
index 46d49bf..6c50b8d 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,4 @@
 Git is a version control system.
 Git is free software.
+
+add more @1st

后面就是相同的步骤:

  • git add添加,这时用git status查看的话,可以知道将被提交的修改包括readme.txt
utane@ubuntu:~/learngit$ git add readme.txt
utane@ubuntu:~/learngit$ git status
ブランチ master
コミット予定の変更点:
  (use "git reset HEAD <file>..." to unstage)

	modified:   readme.txt
  • git commit提交,在git status看到仓库是干净的:
utane@ubuntu:~/learngit$ git commit -m "add more 1st"
[master 0e6ec7c] add more 1st
 1 file changed, 2 insertions(+)
utane@ubuntu:~/learngit$ git status
ブランチ master
nothing to commit, working tree clean

2.1 版本回退

现在我们接着修改,然后add,commit,这样就有了这三个版本:

  • version3:
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
  • version2:
Git is a version control system.
Git is free software.

add more @1st
  • version1:
Git is a version control system.
Git is free software.

通过git log可以查看最近的版本:

utane@ubuntu:~/learngit$ git log
commit eb699b8393c236eabd4a0167c799e12ac70ff566 (HEAD -> master)
Author: utane <lijun.kawasaki@gmail.com>
Date:   Sun Feb 17 19:59:54 2019 -0800

    add more 2nd

commit 0e6ec7c49ebc91ecd9af68a5b0c5964fcbc12df2
Author: utane <lijun.kawasaki@gmail.com>
Date:   Sun Feb 17 19:53:56 2019 -0800

    add more 1st

commit 4568339df27afae26c50dd0d51d63c049429b6f5
Author: utane <lijun.kawasaki@gmail.com>
Date:   Sun Feb 17 19:21:21 2019 -0800

    wrote a readme file

上面显示的结果太繁琐,可以用git log --pretty=oneline输出更简洁的结果:

utane@ubuntu:~/learngit$ git log --pretty=oneline
eb699b8393c236eabd4a0167c799e12ac70ff566 (HEAD -> master) add more 2nd
0e6ec7c49ebc91ecd9af68a5b0c5964fcbc12df2 add more 1st
4568339df27afae26c50dd0d51d63c049429b6f5 wrote a readme file

前面一长串的是版本号。

首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1094adb…(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

  • 比如我们回退到第二个版本,就是上一个版本:
utane@ubuntu:~/learngit$ git reset --hard HEAD^
HEAD is now at 0e6ec7c add more 1st
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st

输出对应文件,可以看到文件回退了。

  • 另外,还可以通过版本号回退,比如:
utane@ubuntu:~/learngit$ git reset --hard 4568
HEAD is now at 4568339 wrote a readme file
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

回退到了第一个版本。

  • 现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?Git提供了一个命令git reflog用来记录你的每一次命令,找到对应的版本号后,又可以回到最新版本了。
utane@ubuntu:~/learngit$ git reflog
4568339 (HEAD -> master) HEAD@{0}: reset: moving to 4568
0e6ec7c HEAD@{1}: reset: moving to HEAD^
eb699b8 HEAD@{2}: commit: add more 2nd
0e6ec7c HEAD@{3}: commit: add more 1st
4568339 (HEAD -> master) HEAD@{4}: commit (initial): wrote a readme file
utane@ubuntu:~/learngit$ git reset --hard eb69
HEAD is now at eb699b8 add more 2nd
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd

2.2 工作区和暂存区

Git和其他的不同之处就是有暂存区的概念。

1. 概念

工作区 working directory:

之前创建的工作目录,就是一个工作区,比如下面的learngit目录:

utane@ubuntu:~/learngit$ ls -ah
.  ..  .git  LICENSE  readme.txt

版本库 Repository:

注意上面,还有一个隐藏目录.git,这个不算工作区,而是Git的版本库,包含了:

  • 称为stage的暂存区
  • 还有Git自动创建的第一个分支 master
  • 以及指向master的一个指针HEAD
utane@ubuntu:~/learngit/.git$ ls
COMMIT_EDITMSG  ORIG_HEAD  config       hooks  info  objects
HEAD            branches   description  index  logs  refs

image

之前提到将文件往Git版本库添加时,分两步:

  1. git add 把文件添加进去,实际上就是把文件修改添加到暂存区
  2. git commit 提交更改,实际上就是把暂存区的所有内容提交到当前分支

2. 实践

  • 先修改和添加文件:
    1. 修改之前readme.txt文件
    2. 添加一个新的文件LICENSE
utane@ubuntu:~/learngit$ vi readme.txt 
utane@ubuntu:~/learngit$ vi LICENSE
  • git status查看状态,可以看到readme.txt被修改了,而LICENSE还无法被追踪
utane@ubuntu:~/learngit$ git status
ブランチ 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

追跡されていないファイル:
  (use "git add <file>..." to include in what will be committed)

	LICENSE

no changes added to commit (use "git add" and/or "git commit -a")
  • git add添加这两个文件后,查看状态,可以看到这两个文件都是下一次的commit对象,因为这两个文件都被放到了stage暂存区:
utane@ubuntu:~/learngit$ git add readme.txt LICENSE 
utane@ubuntu:~/learngit$ git status
ブランチ master
コミット予定の変更点:
  (use "git reset HEAD <file>..." to unstage)

	new file:   LICENSE
	modified:   readme.txt

image

  • 最后用 git commit提交,查看status看到工作区是干净的了
utane@ubuntu:~/learngit$ git commit -m "uderstand stage:add license"
[master 87486c1] uderstand stage:add license
 2 files changed, 3 insertions(+)
 create mode 100644 LICENSE
utane@ubuntu:~/learngit$ git status
ブランチ master
nothing to commit, working tree clean

image

2.3 管理修改

  • 在readme.txt中继续添加一行 add more @4th
utane@ubuntu:~/learngit$ vim readme.txt 
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th
  • 将上面添加了add more @4th的文件放入暂存区:
utane@ubuntu:~/learngit$ git add readme.txt 
  • 继续添加行add more @5th,但是没有git add到暂存区。

  • 将暂存区的commit:

utane@ubuntu:~/learngit$ git commit -m "git tracks changes"
[master 18de63f] git tracks changes
 1 file changed, 1 insertion(+), 1 deletion(-)

这时工作区的文件,是最新的状态:

utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th
add more @5th

如果用git status查看,显示有修改没有被加到暂存区(因为第二次的 5th add more没有加到暂存区),另外暂存区没有需要commit的:

utane@ubuntu:~/learngit$ git status
ブランチ 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")

2.4 撤销修改

1. 撤销工作区的修改

如果在工作区进行了修改,但是还没有git add到暂存区,使用git checkout -- file可以丢弃工作区的修改。

  • 工作区文件中追加了一行stupid boss
utane@ubuntu:~/learngit$ vi readme.txt 
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th
stupid boss

  • git status查看其状态,反应工作区有文件修改了,还没有staged
utane@ubuntu:~/learngit$ git status
ブランチ 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 checkout -- readme.txt将工作区的修改撤销,可以看到最后一行消失了
utane@ubuntu:~/learngit$ git checkout -- readme.txt
utane@ubuntu:~/learngit$ 
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th

2. 撤销暂存区的修改

  • 将readme.txt中添加一行stupid boss,并添加到暂存区,用git status查看,说明已经放到了暂存区,下一步可以commit。
utane@ubuntu:~/learngit$ vi readme.txt 
utane@ubuntu:~/learngit$ git add readme.txt 
utane@ubuntu:~/learngit$ git status
ブランチ master
コミット予定の変更点:
  (use "git reset HEAD <file>..." to unstage)

	modified:   readme.txt
  • git reset HEAD readme.txt可以把暂存区的修改撤销掉(unstage),重新放回工作区:
utane@ubuntu:~/learngit$ git reset HEAD readme.txt
Unstaged changes after reset:
M	readme.txt
  • 在查看仓库状态,看到暂存区没有文件可以commit,暂存区撤销成功了。
utane@ubuntu:~/learngit$ git status
ブランチ 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")
  • 进一步撤销工作区,撤销之后工作区就干净了
utane@ubuntu:~/learngit$ git checkout -- readme.txt
utane@ubuntu:~/learngit$ git status
ブランチ master
nothing to commit, working tree clean
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th

2.5 删除文件

  • 添加一个文件,并commit到仓库中
utane@ubuntu:~/learngit$ vim test.txt
utane@ubuntu:~/learngit$ git add test.txt 
utane@ubuntu:~/learngit$ git commit -m "add test"
[master 47757ee] add test
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt
  • 将工作区的文件删除,然后查看仓库状态,显示有修改没有反应到暂存区,即test.txt的删除动作:
utane@ubuntu:~/learngit$ rm test.txt 
utane@ubuntu:~/learngit$ git status
ブランチ master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	deleted:    test.txt

no changes added to commit (use "git add" and/or "git commit -a")

针对上面的删除,

  1. 一是确实要从版本库中删除文件,那就继续用git rm test.txt将删除反应到暂存区,然后commit,这样就真的删除了。
  2. 另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本,git checkout -- test.txt,git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

3. 远程仓库

  • 使用ssh-keygen -t rsa -C "lijun.kawasaki@gmail.com" 创建SSH Key
utane@ubuntu:~/learngit$ ssh-keygen -t rsa -C "lijun.kawasaki@gmail.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/utane/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/utane/.ssh/id_rsa.
Your public key has been saved in /home/utane/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:ECWmY0c0SRiJNzNaVc2JKHe0EtkNb3kZB8uyGzJnahM lijun.kawasaki@gmail.com
The key's randomart image is:
+---[RSA 2048]----+
|   ..B@O=* .o..  |
|  . X+==+o=o =   |
|   ++*+.. = =    |
|  .. o o . +     |
|        E =      |
|         B o     |
|        + .      |
|       . .       |
|                 |
+----[SHA256]-----+
  • 在用户主目录下回生成.ssh目录,id_ras是私钥,id_rsa.pub是公钥
utane@ubuntu:~/learngit$ cd ..
utane@ubuntu:~$ cd .ssh
utane@ubuntu:~/.ssh$ ls
id_rsa  id_rsa.pub
utane@ubuntu:~/.ssh$ cat id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC46vQk3pMTLkqiqOJr4TCdoOas3VQWBPANSqHABc4Clu/Pzs3vlYDBOq4SzREXMuZw/Uum0y8D6VyxHDrSGkPQXFabYjdWgG/dpfLnaI2RXFlGhcVOteXTZGa5nb6rrHv+61lFqdPK7q2G35YxCVqo9/UAdGQosOHg2rqpWkpV1DedqGB/taxeENHm69+4uIXSANkZqR7CXGyrUayzZvOuOOqNyhnujpW2wtX2/LFY0jd2YuPQYMrLr8r1Zkt23xsLZ8MeYdPelkJmRF73s9DiQg6fNRu+39nbXY5fAyjo1+kArfTqoxthx3a65nEu0ysexyUBV4swKLATYon/lWcp lijun.kawasaki@gmail.com
  • 将上面的SSH 公钥,添加到GitHub中

image

3.1 添加远程库

  • 登录Github,右上角“Create a new repo”按钮,添加一个新的仓库learngit

image

…or create a new repository on the command line

echo "# learngit" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/utanesuke0612/learngit.git
git push -u origin master

…or push an existing repository from the command line

git remote add origin https://github.com/utanesuke0612/learngit.git
git push -u origin master
  • 根据上面的提示,将本地的仓库与之关联:

添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

utane@ubuntu:~/learngit$ git remote add origin https://github.com/utanesuke0612/learngit.git
  • 就可以把本地库的所有内容推送到远程库上:
utane@ubuntu:~/learngit$ git push -u origin master
Username for 'https://github.com': utanesuke0612
Password for 'https://utanesuke0612@github.com': 
Enumerating objects: 20, done.
Counting objects: 100% (20/20), done.
Delta compression using up to 2 threads
Compressing objects: 100% (15/15), done.
Writing objects: 100% (20/20), 1.53 KiB | 785.00 KiB/s, done.
Total 20 (delta 6), reused 0 (delta 0)
remote: Resolving deltas: 100% (6/6), done.
To https://github.com/utanesuke0612/learngit.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。

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

从现在起,只要本地作了提交,就可以通过命令:

$ git push origin master

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

3.2 从远程库克隆

还有一种case,如果是现有远程库,那如何将远程库克隆到本地呢,

假设我们创建了一个新的仓库udacity,下面用命令git clone https://github.com/utanesuke0612/udacitystudy.git克隆一个到本地

utane@ubuntu:~$ git clone https://github.com/utanesuke0612/udacitystudy.git
Cloning into 'udacitystudy'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
utane@ubuntu:~$ ls
devlj             udacitystudy  デスクトップ  ピクチャ
examples.desktop  ダウンロード  ドキュメント  ミュージック
learngit          テンプレート  ビデオ        公開

4. 分支管理

4.1 创建与合并分支

版本回退中,我们知道每次提交,Git都把他们串成一条时间线,这条时间线就是一个分支。截止目前,这个分支就是主分支,即master分支,现在HEAD严格来说是指向master的,master才是指向提交的。

image

每次提交,master分支都会向前移动一步,如下图:

image

当我们创建新的分支,比如dev时,git新建一个指针dev,指向master相同的提交,再把head指向dev,就表示当前分支在dev上。

1. 分支操作过程

如下图,分支创建/切换 -> 分支上修改提交 -> 分支合并 -> 分支删除

image

2. 示例代码

  • 首先创建dev分支,然后切换到dev分支 git checkout -b dev

    后面使用了参数-b表示创建并切换,相当于 git branch devgit checkout dev

utane@ubuntu:~/learngit$ git checkout -b dev
Switched to a new branch 'dev'
  • git branch命令查看当前分支,看到当前是dev分支:
utane@ubuntu:~/learngit$ git branch
* dev
  master
  • 在当前分支上新建文件,并添加后提交:
utane@ubuntu:~/learngit$ vi dev.txt
utane@ubuntu:~/learngit$ git add dev.txt
utane@ubuntu:~/learngit$ git commit -m "test branch dev"
[dev 40ae6e5] test branch dev
 1 file changed, 3 insertions(+)
 create mode 100644 dev.txt
  • 可以看到下面多了一个文件
utane@ubuntu:~/learngit$ ls
LICENSE  dev.txt  readme.txt
  • git checkout master切换到master上,master中没有改文件
utane@ubuntu:~/learngit$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
utane@ubuntu:~/learngit$ ls
LICENSE  readme.txt
  • git merge dev 将dev分支合并到当前的master上
utane@ubuntu:~/learngit$ git merge dev
Updating d720cf6..40ae6e5
Fast-forward
 dev.txt | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 dev.txt
  • git branch -d dev 将dev分支删除
utane@ubuntu:~/learngit$ git branch -d dev
Deleted branch dev (was 40ae6e5).
utane@ubuntu:~/learngit$ git branch
* master

4.2 解决冲突

合并分支的时候,出现冲突是常见的:

  • 创建一个新的分支:
utane@ubuntu:~/learngit$ git checkout -b feature1
Switched to a new branch 'feature1'
utane@ubuntu:~/learngit$ git branch
* feature1
  master

  • 在该分支上修改文件,并提交,
utane@ubuntu:~/learngit$ vim readme.txt 
utane@ubuntu:~/learngit$ git add readme.txt 
utane@ubuntu:~/learngit$ git commit -m "feature1 5th"
[feature1 44a9a3b] feature1 5th
 1 file changed, 2 insertions(+)
  • 切换到master分支,切换的时候会出现提示,说当前的分支比远程(origin)的分支多一次提交:
utane@ubuntu:~/learngit$ git checkout master
Switched to branch 'master'
このブランチは 'origin/master' よりも1コミット進んでいます。
  (use "git push" to publish your local commits)
  • 在master上也对相同的文件进行修改,并commit:
utane@ubuntu:~/learngit$ vi readme.txt 
utane@ubuntu:~/learngit$ git add readme.txt 
utane@ubuntu:~/learngit$ git commit -m "create new master"
[master d19476e] create new master
 1 file changed, 1 insertion(+)
  • 现在分支master和feature都有相同文件的修改,这种合并就可能造成冲突:
utane@ubuntu:~/learngit$ 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查看readme.txt存在冲突,必须手动解决后再提交。
utane@ubuntu:~/learngit$ git status
ブランチ master
このブランチは 'origin/master' よりも2コミット進んでいます。
  (use "git push" to publish your local commits)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")
  • 可以直接查看 readme.txt文件,手动修改,Git用<<<<<<<=======>>>>>>>标记出不同分支的内容,
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th
<<<<<<< HEAD
creating a new branch @master 5th
=======

Createing new branch is quick @feature 5th
>>>>>>> feature1
  • 修改后,再提交:
utane@ubuntu:~/learngit$ vi readme.txt 
utane@ubuntu:~/learngit$ cat readme.txt 
Git is a version control system.
Git is free software.

add more @1st
add more @2nd
add more @3rd
add more @4th
creating a new branch @master 5th
Createing new branch is quick @feature 5th
utane@ubuntu:~/learngit$ git add readme.txt 
utane@ubuntu:~/learngit$ git branch
  feature1
* master
utane@ubuntu:~/learngit$ git commit -m "conflict fixed"
[master e0efded] conflict fixed
utane@ubuntu:~/learngit$ git status
ブランチ master
このブランチは 'origin/master' よりも4コミット進んでいます。
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

4.3 分支管理策略

通常合并分支的时候,Git会用 Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

通过--no-ff方式进行git merge的话,git会在merge上再生成一个新的commit,这样,从分支历史上就可以看出分支信息:

  • 新建并切换到分支 dev上
utane@ubuntu:~/learngit$ git checkout -b dev
Switched to a new branch 'dev'
utane@ubuntu:~/learngit$ ls
LICENSE  dev.txt  readme.txt
  • 修改文件并提交:
utane@ubuntu:~/learngit$ vim readme.txt 
utane@ubuntu:~/learngit$ git add readme.txt 
utane@ubuntu:~/learngit$ git commit -m "add merge"
[dev d64b13e] add merge
 1 file changed, 2 insertions(+)
  • 切换到master上,并合并dev:git merge --no-ff -m "merge with no-ff" dev

    因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

utane@ubuntu:~/learngit$ git checkout master
Switched to branch 'master'
このブランチは 'origin/master' よりも4コミット進んでいます。
  (use "git push" to publish your local commits)
utane@ubuntu:~/learngit$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt | 2 ++
 1 file changed, 2 insertions(+)
  • 通过 git log --graph --pretty=oneline --abbrev-commit 查看分支历史
utane@ubuntu:~/learngit$ git log --graph --pretty=oneline --abbrev-commit
*   ca3e8c5 (HEAD -> master) merge with no-ff
|\  
| * d64b13e (dev) add merge
|/  
*   e0efded conflict fixed
|\  
| * 44a9a3b feature1 5th
* | d19476e create new master
|/  
* 40ae6e5 test branch dev
* d720cf6 (origin/master) delete test
* 47757ee add test
* 18de63f git tracks changes
* 87486c1 uderstand stage:add license
* eb699b8 add more 2nd
* 0e6ec7c add more 1st
* 4568339 wrote a readme file

4.4 Bug分支

软件开发中,bug是常有的,如果我现在的dev分支中开发新功能,但是突然来了一个bug,而dev中的新功能还没有提交。 这时针对这个bug,可以通过一个新的临时分支来修复,修复后,合并分支,并将这个bug分支删除即可。

  • 比如下面,我在dev分支下,暂存区的文件还没有提交:
utane@ubuntu:~/learngit$ git checkout dev
Switched to branch 'dev'
utane@ubuntu:~/learngit$ git branch
* dev
  master

utane@ubuntu:~/learngit$ git status
ブランチ 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")
  • Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作.
utane@ubuntu:~/learngit$ git stash
Saved working directory and index state WIP on dev: d64b13e add merge
  • 然后查看工作区,就是干净的了,可以放心创建新的分支修复bug。
utane@ubuntu:~/learngit$ git status
ブランチ dev
nothing to commit, working tree clean
  • 首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
utane@ubuntu:~/learngit$ git checkout master
Switched to branch 'master'
このブランチは 'origin/master' よりも6コミット進んでいます。
  (use "git push" to publish your local commits)
utane@ubuntu:~/learngit$ git checkout -b issue-101
Switched to a new branch 'issue-101'
  • bug修复,并提交:
utane@ubuntu:~/learngit$ vim readme.txt 
utane@ubuntu:~/learngit$ 
utane@ubuntu:~/learngit$ git add readme.txt 
utane@ubuntu:~/learngit$ git commit -m "fix bug 101"
[issue-101 5508d90] fix bug 101
 1 file changed, 1 insertion(+)
  • 切换到master分支,并将bug分支merge进来:
utane@ubuntu:~/learngit$ git checkout master
Switched to branch 'master'
このブランチは 'origin/master' よりも6コミット進んでいます。
  (use "git push" to publish your local commits)
utane@ubuntu:~/learngit$ git merge --no-ff -m "merged bug fix 101" issue-101
Merge made by the 'recursive' strategy.
 readme.txt | 1 +
 1 file changed, 1 insertion(+)
  • 最后删除bug分支
git branch -d issue-101 
  • 再重新切回dev分支开发新功能
utane@ubuntu:~/learngit$ git checkout dev
Switched to branch 'dev'
utane@ubuntu:~/learngit$ git status
ブランチ dev
nothing to commit, working tree clean
  • 上面的命令查看到工作区是干净的,因为要工作保存到了某个地方,可以如下命令查看
utane@ubuntu:~/learngit$ git stash list
stash@{0}: WIP on dev: d64b13e add merge
  • 接着就是从某个地方将保存的内容恢复了,有两种方式:
      1. git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
      1. git stash pop,恢复的同时把stash内容也删了
utane@ubuntu:~/learngit$ git stash pop
ブランチ 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} (6646bc908bea25d718fd1f3bd969d92c776b7fb5)

4.5 Feature分支

每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。

  • 添加一个新分支feature-vulcan
utane@ubuntu:~/learngit$ git checkout -b feature-vulcan
M	readme.txt
Switched to a new branch 'feature-vulcan'
  • 添加新的功能文件,并commit到对应的新分支
utane@ubuntu:~/learngit$ vim vulcan.py
utane@ubuntu:~/learngit$ 
utane@ubuntu:~/learngit$ git add vulcan.py 
utane@ubuntu:~/learngit$ git commit -m "new feature vulcan"
[feature-vulcan 44240ba] new feature vulcan
 1 file changed, 1 insertion(+)
 create mode 100644 vulcan.py
  • 然后切换到当前的dev开发分支
utane@ubuntu:~/learngit$ git checkout dev
M	readme.txt
Switched to branch 'dev'
  • 这时如果功能取消,不需要合并了,那需要将分支删除,如果是-d的话,提示该分支没有被合并,强制删除的话,需要用-D
utane@ubuntu:~/learngit$ git branch -d feature-vulcan 
error: The branch 'feature-vulcan' is not fully merged.
If you are sure you want to delete it, run 'git branch -D feature-vulcan'.
utane@ubuntu:~/learngit$ git branch -D feature-vulcan 
Deleted branch feature-vulcan (was 44240ba).
utane@ubuntu:~/learngit$ 

4.6 多人协作

当从远程仓库克隆时,实际上Git自动把本地master和远程master对应起来了,远程仓库默认名称是origin。

要查看远程信息用git remote,更详细信息用git remote -v:

utane@ubuntu:~/learngit$ git remote
origin
utane@ubuntu:~/learngit$ git remote -v
origin  https://github.com/utanesuke0612/learngit.git (fetch)
origin  https://github.com/utanesuke0612/learngit.git (push)
utane@ubuntu:~/learngit$ 

1. 推送分支 git push origin dev

utane@ubuntu:~/learngit$ git push origin master
utane@ubuntu:~/learngit$ git push origin dev

master是主分支,需要时刻同步,dev是开发分支也需要时刻同步,而bug和feature分支就不一定需要推送了。

2. 抓取分支

在另一台windows电脑上,克隆一个Github上相同的仓库learngit到本地:

  • 克隆git clone https://github.com/utanesuke0612/learngit.git
utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git
$ pwd
/c/Users/utane/OneDrive/Git

utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit
$ git clone https://github.com/utanesuke0612/learngit.git
Cloning into 'learngit'...
remote: Enumerating objects: 40, done.
remote: Counting objects: 100% (40/40), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 40 (delta 19), reused 39 (delta 18), pack-reused 0
Unpacking objects: 100% (40/40), done.
  • 默认情况下,只能看到本地的master分支,可以用git branch查看:
utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit
$ git branch
* master
  • 要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是用命令创建本地dev分支:git checkout -b dev origin/dev
utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit (master)
$ git checkout -b dev origin/dev
Switched to a new branch 'dev'
Branch dev set up to track remote branch dev from origin.

utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit (dev)
$ git branch
* dev
  master
  • 然后在该分支上开发,并将dev分支push到远程git push origin dev
utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit (dev)
$ vi win10dev.txt

utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit (dev)
$ git add win10dev.txt
warning: LF will be replaced by CRLF in win10dev.txt.
The file will have its original line endings in your working directory.

utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit (dev)
$ git commit -m "add file from win10"
[dev f8f59b3] add file from win10
 1 file changed, 1 insertion(+)
 create mode 100644 win10dev.txt

utane@LAPTOP-4KOGTOIU MINGW64 ~/OneDrive/Git/learngit (dev)
$ git push origin dev
fatal: HttpRequestException encountered.
   ▒▒▒̗v▒▒▒̑▒▒M▒▒▒ɃG▒▒▒[▒▒▒▒▒▒▒▒▒܂▒▒▒▒B
Username for 'https://github.com': utanesuke0612
wanCounting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 282 bytes | 282.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/utanesuke0612/learngit.git
   d64b13e..f8f59b3  dev -> dev

3. 解决冲突

如果你的同事在window机器上,修改并push了dev.txt,但是你linux本地没有反映到最新的,并继续在旧版本上修改:

  • 修改并提交dev.txt文件
utane@ubuntu:~/learngit$ cat dev.txt 
itet

test
utane@ubuntu:~/learngit$ vi dev.txt 
utane@ubuntu:~/learngit$ 
utane@ubuntu:~/learngit$ 
utane@ubuntu:~/learngit$ git add dev.txt 
utane@ubuntu:~/learngit$ git commit -m "conflict"
[dev 7153e6a] conflict
 1 file changed, 2 insertions(+)
  • 试着提交的时候,显示文件有冲突无法合并,需要先git pull

    如果 git pull 失败,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接,git branch --set-upstream-to=origin/dev dev

utane@ubuntu:~/learngit$ git push origin dev
Username for 'https://github.com': utanesuke0612
Password for 'https://utanesuke0612@github.com': 
To https://github.com/utanesuke0612/learngit.git
 ! [rejected]        dev -> dev (fetch first)
error: failed to push some refs to 'https://github.com/utanesuke0612/learngit.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  • 使用git pull后,提示发生了冲突,需要手动解决
utane@ubuntu:~/learngit$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/utanesuke0612/learngit
   f8f59b3..572f4f7  dev        -> origin/dev
Auto-merging dev.txt
CONFLICT (content): Merge conflict in dev.txt
Automatic merge failed; fix conflicts and then commit the result.
  • 手动解决冲突后,继续 git add -> git commit -> git push origin dev远程push到github
utane@ubuntu:~/learngit$ vi dev.txt 
utane@ubuntu:~/learngit$ cat dev.txt 
itet

test

confilict multi@linux 1st
conflict multi@wind 1st
utane@ubuntu:~/learngit$ git add dev.txt 
utane@ubuntu:~/learngit$ git commit -m "fix conflict"
[dev 98b8b9a] fix conflict
utane@ubuntu:~/learngit$ git push origin dev
Username for 'https://github.com': utanesuke0612
Password for 'https://utanesuke0612@github.com': 
Enumerating objects: 20, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 2 threads
Compressing objects: 100% (10/10), done.
Writing objects: 100% (11/11), 1.17 KiB | 1.17 MiB/s, done.
Total 11 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4), completed with 1 local object.
To https://github.com/utanesuke0612/learngit.git
   572f4f7..98b8b9a  dev -> dev
utane@ubuntu:~/learngit$ 

4.7 Rebase

廖老师的这一章讲得不是很好懂,参考官方文档-3.6 Git 分支 - 变基Git Community Book 中文版-rebase

实际碰到这种情况再补上。

5. 标签管理

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。 tag是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。

5.1 创建标签

  • 在Git中打标签非常简单,首先,切换到需要打标签的分支上:
utane@ubuntu:~/learngit$ git branch
* dev
  master
utane@ubuntu:~/learngit$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
  • 敲命令git tag <name>就可以打一个新标签,可以用命令git tag查看所有标签:
utane@ubuntu:~/learngit$ git tag v1.0
utane@ubuntu:~/learngit$ git tag
v1.0
  • 默认标签是打在最新提交的commit上的,如果要打在历史版本上怎么办:
utane@ubuntu:~/learngit$ git log --pretty=oneline --abbrev-commit
f4b6a01 (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
5508d90 fix bug 101
ca3e8c5 merge with no-ff
d64b13e add merge
e0efded conflict fixed
d19476e create new master
44a9a3b feature1 5th
40ae6e5 test branch dev
d720cf6 delete test
47757ee add test
18de63f git tracks changes
87486c1 uderstand stage:add license
eb699b8 add more 2nd
0e6ec7c add more 1st
4568339 wrote a readme file
  • 通过上面的命令,找到历史版本号,使用相同命令就可以打tag
utane@ubuntu:~/learngit$ git tag v0.9 5508
utane@ubuntu:~/learngit$ git tag
v0.9
v1.0
utane@ubuntu:~/learngit$ git show v0.9
commit 5508d9008bd1c81854942237aecae918d6786e6f (tag: v0.9)
Author: utane <lijun.kawasaki@gmail.com>
Date:   Mon Feb 18 02:02:13 2019 -0800

    fix bug 101

diff --git a/readme.txt b/readme.txt
index c17f62d..c844ac8 100644
--- a/readme.txt
+++ b/readme.txt
@@ -9,3 +9,4 @@ creating a new branch @master 5th
 Createing new branch is quick @feature 5th
 
 no-ff @dev 5th
+fixed the bug@issue-101 6th
  • 还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
utane@ubuntu:~/learngit$ git tag -a v0.8 -m "ver0.8 released" ca3e
utane@ubuntu:~/learngit$ git tag
v0.8
v0.9
v1.0
utane@ubuntu:~/learngit$ git show v0.8
tag v0.8
Tagger: utane <lijun.kawasaki@gmail.com>
Date:   Mon Feb 18 22:43:25 2019 -0800

ver0.8 released

commit ca3e8c5713bbbb6ba91da16fdc08d02a5d4bc6f2 (tag: v0.8)
Merge: e0efded d64b13e
Author: utane <lijun.kawasaki@gmail.com>
Date:   Mon Feb 18 01:48:00 2019 -0800

    merge with no-ff

5.2 操作标签

  • 如果标签打错了,可以删除,git tag -d v0.8
utane@ubuntu:~/learngit$ git tag -d v0.8
Deleted tag 'v0.8' (was 2132c19)
  • 如果要推送某个标签到远程,使用命令git push origin v1.0
utane@ubuntu:~/learngit$ git push origin v1.0
Username for 'https://github.com': utanesuke0612
Password for 'https://utanesuke0612@github.com': 
Total 0 (delta 0), reused 0 (delta 0)

To https://github.com/utanesuke0612/learngit.git
 * [new tag]         v1.0 -> v1.0
  • 一次性推送全部尚未推送到远程的本地标签git push origin --tags
utane@ubuntu:~/learngit$ git push origin --tags
Username for 'https://github.com': utanesuke0612
Password for 'https://utanesuke0612@github.com': 
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/utanesuke0612/learngit.git
 * [new tag]         v0.9 -> v0.9
utane@ubuntu:~/learngit$ git tag
v0.9
v1.0
  • 如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
utane@ubuntu:~/learngit$ git tag -d v0.9
Deleted tag 'v0.9' (was 5508d90)
  • 然后,从远程删除。删除命令也是push,但是格式如下git push origin :refs/tags/v0.9
utane@ubuntu:~/learngit$ git push origin :refs/tags/v0.9
Username for 'https://github.com': utanesuke0612
Password for 'https://utanesuke0612@github.com': 
To https://github.com/utanesuke0612/learngit.git
 - [deleted]         v0.9
utane@ubuntu:~/learngit$ 

6. 自定义Git

我们已经配置了user.name和user.email,实际上,Git还有很多可配置项。

比如,让Git显示颜色,会让命令输出看起来更醒目:

utane@ubuntu:~$ git config --global color.ui true
utane@ubuntu:~/learngit$ git status
ブランチ master
Your branch is up to date with 'origin/master'.

6.1 忽略特殊文件

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦。

在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

所有配置文件可以直接在线浏览:https://github.com/github/gitignore,可以自行根据需要修改

  • 添加.gitignore文件,并写入Desktop.ini为被忽略文件:
utane@ubuntu:~/learngit$ vi .gitignore
utane@ubuntu:~/learngit$ git add .gitignore 
utane@ubuntu:~/learngit$ git commit -m "add ignore filelist"
[master ac88632] add ignore filelist
 1 file changed, 6 insertions(+)
 create mode 100644 .gitignore
  • 新建一个文件Desktop.ini,然后git add的话,显示无法被追加,另外提示我们可以通过git add -f Desktop.ini强制添加:
utane@ubuntu:~/learngit$ vi Desktop.ini
utane@ubuntu:~/learngit$ git add Desktop.ini 
The following paths are ignored by one of your .gitignore files:
Desktop.ini
Use -f if you really want to add them.
  • 需要找出来到底哪个规则写错了,可以用git check-ignore命令检查,可以看到是第二行限定了它:
utane@ubuntu:~/learngit$ git check-ignore -v Desktop.ini
.gitignore:2:Desktop.ini  Desktop.ini

6.2 配置别名

通过配置别名,可以使输入简化,比如配置下面第一个命令后,输入git st就可以与git status一样效果了。

$ git config --global alias.st status
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
  • 撤销修改,命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区。可以简化如下:
$ git config --global alias.unstage 'reset HEAD'
$ git unstage test.py

上面就可以撤除暂存区的修改了。

  • 配置一个git last,让其显示最后一次提交信息:
$ git config --global alias.last 'log -1'
  • 还有更实用的输出log命令,直接使用git lg就不用记一长串命令了:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中。

  • 如果需要删除的话,直接编辑文件删除对应的alias行:
utane@ubuntu:~/learngit$ git config alias.last 'log -1'
utane@ubuntu:~/learngit$ cat .git/config 
[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
  logallrefupdates = true
[remote "origin"]
  url = https://github.com/utanesuke0612/learngit.git
  fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
  remote = origin
  merge = refs/heads/master
[branch "dev"]
  remote = origin
  merge = refs/heads/dev
[alias]
  last = log -1

6.3 搭建Git服务器

搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,通过几条简单的apt命令就可以完成安装。

  • 安装git
utane@ubuntu:~$ sudo apt-get install git
[sudo] utane のパスワード: 
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
git はすでに最新バージョン (1:2.19.1-1ubuntu1.1) です。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 14 個。
  • 创建一个git用户,用来运行git服务sudo adduser git

  • 创建证书登录:

收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。

  • 先选定一个目录/home/srv作为Git仓库
utane@ubuntu:/home$ sudo mkdir srv
utane@ubuntu:/home$ ls
git  srv  utane
  • 初始化Git仓库:
sudo git init --bare sample.git
  • 把owner改为git:
sudo chown -R git:git sample.git
  • 禁用shell登录:

    出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:

git:x:1001:1001:,,,:/home/git:/bin/bash

改为:

git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
  • 之后,每个登录了公钥的用户,就可以通过git clone命令来克隆远程仓库了:
$ git clone git@server:/srv/sample.git
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.

7. 使用GitHub

可以把github上一个任意的项目folk到自己账号下面,然后clone到本地,如下图:

image

比如下面我folk了著名的pandas代码,并clone到本地:

utane@ubuntu:~/learngit$ cd ..
utane@ubuntu:~$ git clone https://github.com/utanesuke0612/pandas.git
Cloning into 'pandas'...
remote: Enumerating objects: 130880, done.
...

修改之后可以,最后在GitHub上发送一个pull Request,等待对方接受。