Git 马克

自从 Github 官方的客户端崩了几次之后,决定彻底卸载,改用 Git 命令的方式进行项目更新。用着用着发现,Git 还有好多没搞明白的东西,这里统一做一个记录。

0 关于 Git

这里记录的东西来自官方的 PDF 与一些帖子。

git

这里有一些基本概念和操作,上图很明确的解释了。

  • 工作区 workspace:项目文件夹,即时性强,对文件的所有更改都会立刻体现在这里
  • 版本库 .git:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本数据库
  • 暂存区 index/stage:git add以后,当前对文件的更改会保存到这个区
  • 本地仓库 local repository:git commit 以后,当前暂存区里对文件的更改会提交到本地仓库;git pull 之后远程仓库领先的 commit 会同步到本地仓库
  • 远程仓库 remote repository:远程仓库名一般叫 origin,git push以后,本地仓库里领先于远程仓库的 commit 会同步到远程仓库

1 git config 设置

1.1 常用配置

.gitconfig 文件在 C:\Users\$USER 目录下,储存一些 Git 的参数属性,需要 Admin 权限进行更改。设置隐藏属性不影响权限。

1
2
3
4
5
6
7
8
9
# show all config
git config --global -l

# user profile
git config --global user.name "Tommy"
git config --global user.email tommy.zhou@sap.com

# editor Code
git config --global core.editor vim

1.2 设置 alias

设置 editor 这里,如果需要设置 VSCode,把安装路径添加到 PATH,使用 Code 作为键值就可,其他的编辑器也是类似的。另外Git 可以设置快捷指令。

1
2
3
4
5
6
7
8
9
10
# alias
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ad add
git config --global alias.ci commit
git config --global alias.ps push
git config --global alias.pl pull
git config --global alias.st status
git config --global alias.lo log
git config --global alias.unstage 'reset HEAD --'

2 repository 操作

2.1 初始化与状态查询

对一个进行版本管理的工具,常用操作在这里。显示本地与远程项目的交互,然后单独记录一下 branch 相关的一些配置。

1
2
3
4
5
6
7
8
9
# initialize a repo
git init

# clone from reomote
git clone <url> <localname>

# check changing status
git status
git status -s

-s 参数可以用更简洁的形式进行显示。注意,这将显示左右两栏,左侧是 local repository 的状态,右侧是工作区的状态。A 代表添加,M 代表有修改。

2.2 文件提交与忽略

检查文件状态的时候,git 不会检查未被跟踪的文件,比如刚刚建立的新文件。这个时候需要将文件加入到索引区,进行跟踪。在 git init 之后往往也需要进行一次 add 操作。

1
2
# add new files to track
git add <filename>

在 add 的时候需要忽略一些不必要的文件,因此会有 .gitignore 文件。参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# vim .gitignore to edit
cat .gitignore

# ignore all .a files
*.a

# but do track lib.a, even though you're ignoring .a files above !lib.a

# only ignore the TODO file in the current directory, not subdir/TODO /TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf

2.3 更改内容对比

可以查看工作区、本地仓库里面文件的更新对比。这将会打开默认的 editor。可以用外接工具打开和查看这些对比。

1
2
3
4
5
6
7
8
# check the diff of workspace
git diff

# check the diff of local repo
git diff --staged

# using external tool
git difftool --too=<tool>

2.4 提交更新的内容

commit 提交文件的更新内容之后,需要附加一条 message 来进行标注。可以在 commit 弹出的默认编辑器中进行,也可以直接在指令中 -m 附加 message 的内容。

1
2
3
4
5
6
7
8
# commit
git commit

# append the message
git commit -m "Message Content"

# automatically add
git commit -a -m "Message Content"

注意这里提交的内容仅从 index/stage 到 local repository,没有 add 的文件不会进行提交。当然也可以使用 -a 来自动添加,但这只能添加所有开始跟踪的文件。

2.5 删除文件

删除文件的流程应该是,同时删除工作区和缓存区的文件,再进行 commit。rm 指令仅移除工作区文件,git rm 指令可以移除工作区与缓存区的文件。使用 –cache 则可以仅移除缓存区文件,这一般用于移除不小心提交但实际需要忽略的文件。

1
2
3
4
5
6
7
8
9
# remove files in workspace
rm <filename>

# remove files in both workspace and stage
git rm <filename>
git rm -r .

# remove files in stage
git rm <filename> --cache

2.6 移动文件

Git 并不记录文件的移动,mv 指令等价于 rm 与 add 指令的组合。

2.7 查看文件更改历史

git log 指令可以查看 commit 历史,这部分可选参数比较多,查看文档。

1
2
3
# check commit history
git log
git log -p

2.8 撤销操作

几乎所有的操作都是可以撤销的。如果在 commit 之后发现有忘记 add 的文件,可以这样将文件添加进来,保持仅一次的 commit。使用 git reset 来取消文件的缓存,git checkout 来撤销文件的更改,分别撤销缓存区与工作区的更改。

1
2
3
4
5
6
7
8
9
10
# add forgotten files to last commit
git commit -m 'initial commit'
git add forgotten_file
git commit --amend

# unstage files
git reset HEAD <filename>

# revert modified files
git checkout -- <filename>

2.9 与远程仓库交互

本地操作好了就可以与远端仓库交互了。shortname 可以在后面的指令中替代跟在后面的 url。remove 的指令常常用于移除一些不再参与的 remote。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# shwo remote repo
git remote
git remote -v

# same as git clone
git remote add <shortname> <url>

# get remote to local, requires manually merge
git fetch <remote>

# automatically fetch and pull
git pull <remote>

# pushing to remotes, default to origin master
git push <remote> <branch>

# inspecting a remote
git remote show <remote>

# rename remote
git remote rename <pb> <remote>

# removing remote
git remote remove pb

3 branch 相关操作

branch 的操作很有意思。branch 仅仅是一个可移动的指针,指向某一次的 commit,master 也是一个特殊的指针,默认在 init 的时候创建。创建一个新的 branch时,默认指向当前的 commit。指向指针的指针 HEAD 来指明当前所在的 branch。

01

3.1 分支创建与切换

分支创建的时候,默认指向当前最新的 commit。切换分支会改变工作区的文件。创建新的分支的时候会复制当前分支所有的文件和 commit 历史,因此需要 fork 其他人提交历史的时候,可以进行:1 为项目添加别人的 remote;2 git checkout 到所需的分支;3 在这里执行 git checkout -b <name>。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# create a new branch
git branch <branchname>

# list all branches
git branch
git branch -a
git branch -v

# already merged branch
git branch --merged
git branch --no-merged

# switching branches
git checkout <branchname>
git checkout -b <branchname>

3.2 分支合并

切换到合并的分支,merge 被合并的分支,之后可以删除被合并的分支。

1
2
3
4
5
6
7
8
9
# merge branches
git checkout master
git merge <branchname>

# delete branch
git branch -d <branch>

# delete remote branch
git push origin --delete <branchname>

如果合并的时候遇到了分支之间的冲突,那么 git 会提示冲突的存在,需要手动解决,但是此时已经创建了一个 merge commit,再用 status 查看存在冲突的 path。另外 git 还会在冲突的文件加入 standard conflict-resolution markers,标记冲突。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# merge conflict
git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

# check status now
git status
On branch master
You have unmerged paths.(fix conflicts and run "git commit")

Unmerged paths:(use "git add <file>..." to mark resolution)
    both modified:      index.html
 
no changes added to commit (use "git add" and/or "git commit -a")

# standard conflict-resolution markers
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
	please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

# external tool
git mergetool

解决冲突需要移除冲突标记,将整块的内容替换为选择的那个分支的这部分的内容。

后面还有许多高端的操作,一般也用不上,先记录这么多了,有需要的时候再查阅官方文档。