Git学习笔记

| 分类 技术随笔 

Git和版本控制,在听雨技术部的时候气体就一直给我们强调,但我平时也就仅仅会使用基础的git操作。也是不需要和很多人协作,平时做的事也不用什么分支之类进阶的功能。现在BasicCAT打算使用git来进行协作翻译,得深入了解一下。

原理方面可以看progit这本书,我这里主要讲操作。

基本操作:

  • 新建空的仓库:git init。这样可以建立.git文件夹。
  • 添加文件:git add filename,这样以后会记录这个文件的变化
  • 查看工作状态:git status,可以显示当前工作区的状态。
  • 提交记录:git commit -m "commit message",如果不加-m,会跳出编辑器界面让你手动输入提交信息。
  • 查看工作区的文件有哪些变动:git diff。适用于还没有用add来stage文件的情况。如果add并commit了,需要使用git show
  • 给仓库打标签:git tag 给标签取的名字,可以标记重要节点的commit。
  • 查看记录:git log,可以显示commits的历史。

如果commit后想再修改这个commit,比如添加文件,修改commit message,可以使用git commit --amend

下面是远程git仓库相关操作。

  • 新建一个bare仓库,没有工作文件夹,可以用作远程仓库使用:git init --bare
  • 给本地仓库添加远程仓库记录:git remote add origin https://github.com/xulihang/git-playground.git,名字叫做origin。
  • 将本地的修改提交到远程仓库:git push
  • 将远程仓库的新内容下来到本地仓库:git fetch
  • 将远程仓库的新内容下来到本地仓库并进行合并操作:git pull
  • 克隆远程仓库到本地:git clone https://github.com/xulihang/git-playground.git,同时会添加remote记录。

进阶操作

reset

以下是reset的命令说明

PS D:\git\playground> git reset -h
usage: git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]
   or: git reset [-q] [<tree-ish>] [--] <paths>...
   or: git reset --patch [<tree-ish>] [--] [<paths>...]

    -q, --quiet           be quiet, only report errors
    --mixed               reset HEAD and index
    --soft                reset only HEAD
    --hard                reset HEAD, index and working tree
    --merge               reset HEAD, index and working tree
    --keep                reset HEAD but keep local changes
    --recurse-submodules[=<reset>]
                          control recursive updating of submodules
    -p, --patch           select hunks interactively
    -N, --intent-to-add   record only the fact that removed paths will be added later

用法示例:git reset HEAD~1,HEAD指向前一次commit,但本地文件没有变动。而添加–hard选项后,工作区的本地文件也会回退。这里HEAD~1可以用具体的commit代码进行替换。

revert

和git reset删除显示的commit记录不一样,revert是添加commit。只是新的commit提交后,内容是进行回滚后的内容,这样每次撤销的记录也会保存下来。

用法示例:git revert HEAD,撤销当前HEAD对应的commit的内容。

branch 和 merge

git可以高效地使用分支,我们平时可以把代码提交到测试分支,比如叫testing,测试可以发布后再提交到生产线分支,比如默认的master。

  • 建立分支:git branch testing
  • 切换到该分支:git checkout testing,工作区的文件会变成该分支版本的

以上两条命令和这条命令效果一样:git checkout -b testing

如果要将testing分支的修改合并到master分支,运行以下命令:

PS D:\git\playground> git checkout master
PS D:\git\playground> git merge testing
Updating fe185c0..5ed6517
Fast-forward
 readme.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

因为testing分支和master的父commit是一样的,所以显示Fast-forward,本质是将master的head指向testing的最新commit。

如果master又有了提交,这样合并testing时可能会产生冲突:

PS D:\git\playground> git merge testing
Auto-merging readme.md
CONFLICT (content): Merge conflict in readme.md
Automatic merge failed; fix conflicts and then commit the result.

运行git status,会有如下内容:

PS D:\git\playground> git status
On branch master
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.md

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

这时打开出现冲突的文件,会是以下内容:

<<<<<<< HEAD
Hello!!
你好!
=======
Hello!!!
>>>>>>> testing

我们需要手动解决冲突,然后进行git add和git commit就不会提示错误了。解决冲突只需保留需要的内容,然后把添加的注释删去。

利用git log --pretty=oneline --graph命令可以以字符图像的形式显示分支合并的结果。可以看到master合并了testing的内容,新建了一个merge后的commit记录。

PS D:\git\playground> git log  --pretty=oneline --graph
*   34f98a17ba05f3b0a1e7b2c650eae7c2a58ed774 (HEAD -> master) Merge branch 'testing'
|\
| * bc1d74f900a7036b06f557ee5872d129256a91cf (testing) update
* | 1db49bbdc2f018b7dc9aac3d59f9a4c61666f6a3 update
|/
* 5ed65172d3a7a984635691ea8f733a30229a627f update
* fe185c0ae591b4067dfe9e5e193b6a33418c5264 Revert "update"
* 62526fc0ee0c16e636e2d690300909275920bd30 update
* 2e19cc94366869c5eb2df02862bfd6c20be01524 (tag: dd) init

rebase

rebase和merge的功能相似,不过使用merge会生成较为复杂的历史,而rebase则保持commit只有一条历史。

用的还是上面的例子,以下代码将testing的基础commit变成master分支最新的commit。同样会提示冲突。

PS D:\git\playground> git checkout testing
Switched to branch 'testing'
PS D:\git\playground> git rebase master
First, rewinding head to replay your work on top of it...
Applying: update
Using index info to reconstruct a base tree...
M       readme.md
Falling back to patching base and 3-way merge...
Auto-merging readme.md
CONFLICT (content): Merge conflict in readme.md
error: Failed to merge in the changes.
Patch failed at 0001 update
Use 'git am --show-current-patch' to see the failed patch

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

按照提示解决冲突,可以完成rebase。

我们切换回master分支,把testing分支merge进来:

PS D:\git\playground> git checkout master
Switched to branch 'master'
PS D:\git\playground> git merge testing
Updating 493b0ce..45319f7
Fast-forward
 readme.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

因为已经rebase过了,所以merge显示的是Fast-forward。我们再查看commit记录会是这样的,一条线,比较简洁:

PS D:\git\playground> git log  --pretty=oneline --graph
* 45319f7b3c7f35ebdaf816a62e7c9ff353dded10 (HEAD -> master, testing) update
* 493b0ced12b54bae7acd0a0cedf068481ac3987f update
* 5ed65172d3a7a984635691ea8f733a30229a627f update
* fe185c0ae591b4067dfe9e5e193b6a33418c5264 Revert "update"
* 62526fc0ee0c16e636e2d690300909275920bd30 update
* 2e19cc94366869c5eb2df02862bfd6c20be01524 (tag: dd) init

checkout

checkout除了切换分支,把仓库里的文件提取到工作文件夹,还可以撤销对工作区没有add过的文件进行的修改。


上一篇     下一篇