git快速入门

git快速入门

spiritTrance

前言的前言

由于关于Git的介绍实在过多,反复记录意义不大,因此本文将不再作大幅度更新(大概弃坑了,可能会介绍一些不太常见的内容,例如钩子函数)。下面是一些学习资料的推荐:

  • Learning Git :强烈推荐!交互式的操作和可视化的界面,仅需三个小时就可以完全掌握Git。
  • 我看谁还不懂 Git !(万字干货) 知乎上刷到的一篇博文,很详细细致,有大量绘制的图。
  • Pro Git :有大佬推荐,貌似很出名,但是本人没有看过。

本文以后主要更新一些作者在实践过程中遇到的各种各样的问题(如100MB文件提交限制),以及一些进阶内容(说白了就是很少用的内容),如钩子函数。

在学习过程中,带着问题更有效,下面是作者提出的一些基础问题,在学习过程中需要思考:

  • Git是什么?Github又是什么?两者有什么关系?你还知道哪些代码托管平台和版本管理工具?
  • 本地仓库是如何管理的?工作区,暂存区等概念是什么?
  • 本地仓库和远程仓库的概念是什么?两者间如何交互?
  • 本地仓库的分支是如何管理的?有哪些常见操作?这些操作需要注意什么?什么时候会出现数据丢失的风险?
  • 为什么不建议在仓库中提交Word,图片等文件?

希望在学习过程中思考这些问题。当然,如果仅仅是刚开始入门,那么仅需参考本文的Git及代码托管平台初步使用一章即可。

【挖坑】后面想探索一下:
- 基于github的多人协作,重点介绍分支保护,PR,issue等等,预计会开个新帖
- github action这些玩意是什么东西(跟博客有关),以及Wiki,release等等,预计会开个新贴介绍。

前言

如果:

  • 您是git用户的新手,希望能快速上手使用,那么阅读完Git及代码托管平台初步使用章节即可
  • 如果您遇到了任何问题,请移步疑难杂症记录,那里记录了作者使用git以来的各种问题,希望能帮助倒您
  • 如果您需要进行多人协作的开发,请移步多人协作
  • 如果您需要查找常用指令的各种用法及作用,请移步常见操作记录,并善于运用git xxx --help指令(其中xxx是您想使用的操作)。
  • 如果你需要熟练操作,可以尝试这个

Git及代码托管平台初步使用

本节介绍单人从git开始到拥有一个完整的仓库,并如何将本地数据同步上去。

  • Git:版本控制工具;GitHub/Gitee:社交代码托管平台
  • 因此将代码托管到github和gitee的步骤大同小异。本文以github为例,介绍如何使用Git及托管平台。

准备步骤

这里以Windows11操作系统为例,介绍本地git的环境配置1
开始之前,您需要

  • 注册github /gitee 账号,并牢记昵称和邮箱,并不要轻易更改昵称和密码(修改后会有坑)
  • 下载git 工具,作者用的是2.37.3版本,安装过程根据提示即可,初学者可以一直点next。
  • [可选]下载Git的图形化操作工具TortoiseGit

以上操作执行后,就可以配置环境了。首先右键打开菜单,找到Git Bash Here选项。打开终端,输入以下内容(引号内内容替换为注册账号时所用信息即可,分别为昵称和邮箱):

1
2
git config --global user.name "yourName"              # example: git config --global user.name "spiritTrance"
git config --global user.email "yourEmail@email.com" # example: git config --global user.name "15781xxxxx@qq.com"

之后在本地创建ssh key:

1
ssh-keygen -t rsa -C "yourEmail@email.com"      # example: ssh-keygen -t rsa -C "15781xxxxx@email.com"

之后连续敲击三次回车键后会生成两个隐藏文件,在windows11环境下(其他环境需要留意cmd的提示)放置在该路径:C:\Users\<你的电脑用户名>\.ssh,在.ssh下找到 id_rsa.pub文件,复制里面的内容。然后登录托管平台,进入设置 项目,在侧边栏找到SSH and GPG keys,添加SSH key,在Key里面粘贴 id_rsa.pub文件里的内容,Title内容可以随意填写。

到现在为止,你已经在本地部署好了git,已经能够离线进行版本控制了。

仓库创建及同步

这一小节主要介绍本地仓库和远程仓库的同步。

托管平台上的仓库创建

  • 登录github,点击个人头像,在下拉菜单里找到Your repositories,这里就是你的远程仓库了。
  • 然后找到New,开始创建你的仓库 ,按照其要求填写即可。(注意:在github上,如果勾选需要README.md,则分支名为main,否则为master)
  • 关于license协议的选择,请看这篇文章 。一般来说初学者选择MIT协议,可以规避很多问题。

本地仓库创建与远程仓库推送

当github/gitee上的远程仓库创建好后,如果里面没有任何文件,那么github/gitee会出现以下提示帮助你快速上手。所以你可以在你的工作目录下面打开命令行,输入以下内容,对应含义请见注释.

在命令行创建新的仓库的步骤:

1
2
3
4
5
6
7
echo "# blogPostArchive" >> README.md   # 添加README.md文件,里面一般用于介绍你的仓库
git init # 初始化本地仓库
git add README.md # 将README.md文件加入本地仓库的暂存区,可以加`.`符号表示加入当前工作目录下的所有文件(但.gitignore文件中设置的文件除外)
git commit -m "first commit" # 将暂存区里面的内容提交,并加上"first commit"的注释
git branch -M main # 命名分支名为main(默认为master)
git remote add origin git@github.com:[你的用户名]/[你的远程仓库名].git # 操作远程仓库,后续推送需要 例:git remote add origin git@github.com:spiritTrance/gitlearning.git
git push -u origin main # -u 设置推送流,origin是远程仓库别名,main是本地仓库分支名(特别注意本地分支名是main还是master)

在命令行推送本地已有的仓库的步骤:

1
2
3
git remote add origin git@github.com:spiritTrance/gitlearning.git
git branch -M main
git push -u origin main

值得一提的是,一个仓库一般都会有README.md文件和.gitignore文件2:

提示

  • README.md文件是github上绝大多数都会有的文件。文件名为README.md的文件会在代码托管平台上,直接在页面中显示。这一文件的作用主要是介绍当前仓库的内容。

  • .gitignore文件的作用是在远程推送的时候,避免某些文件被纳入版本管理。一般来说,某些涉及机密的文件,以及单个文件大小过大(50MB会出现警告,100MB会被禁止推送,需要使用git LFS工具)的文件是需要加进来的,以及.gitignore文件本身。.gitignore文件的编写示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # *.a             表示忽略所有 .a 结尾的文件
    # !lib.a 表示但lib.a除外
    # /TODO 表示仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
    # build/ 表示忽略 build/目录下的所有文件,过滤整个build文件夹;
    # doc/*.txt 表示会忽略doc/notes.txt但不包括 doc/server/arch.txt

    # bin/: 表示忽略当前路径下的bin文件夹,该文件夹下的所有内容都会被忽略,不忽略 bin 文件
    # /bin: 表示忽略根目录下的bin文件
    # /*.c: 表示忽略cat.c,不忽略 build/cat.c
    # debug/*.obj: 表示忽略debug/io.obj,不忽略 debug/common/io.obj和tools/debug/io.obj
    # **/foo: 表示忽略/foo,a/foo,a/b/foo等
    # a/**/b: 表示忽略a/b, a/x/b,a/x/y/b等
    # !/bin/run.sh 表示不忽略bin目录下的run.sh文件
    # *.log: 表示忽略所有 .log 文件
    # config.php: 表示忽略当前路径的 config.php 文件

    # /mtk/ 表示过滤整个文件夹
    # *.zip 表示过滤所有.zip文件
    # /mtk/do.c 表示过滤某个具体文件

    但需要注意的是,如果你是在途中加入的.gitignore,之前的提交信息并不会删除,删除之前的提交记录是一件比较麻烦的事情。因此,请务必养成写.gitignore的好习惯,尤其是可能产生的大文件。

  • 扩展阅读:git是如何实现版本管理的?git add, git commit时发生了什么?

本地仓库及远处仓库更新

如果工作目录下的文件有更新,需要进行版本管理,则操作如下:

1
2
3
git add . # 将工作目录下的所有文件加入本地git repo的缓存区
git commit -m "update Message" # 提交更新信息
git push # 推送到远程仓库的main分支

如果上面的三个操作都会了,其实已经可以满足日常单人开发的使用了。但如果是多人开发,建议按照如下步骤进行。

1
2
3
4
5
git fetch # 将代码托管平台上的文件fetch下来
git add . # 将工作目录下的所有文件加入本地git repo的缓存区
git commit -m "update Message" # 提交更新信息
git merge # 合并
git push origin main # 推送到远程仓库的main分支

下面是一些QA:

  • Q1:为什么需要用git fetch而不是git pull?
  • A1:原因见此
  • Q2:git merge出现冲突如何解决?
  • A2:因为各种原因(常见于多人协作),merge后在上面最后一条执行完后会出现冲突问题,如下图所示:

此时你需要打开冲突的文件(本地文件图标右下角为黄色感叹号的文件):

可以看到图中有两个来源的信息,需要将带有<<<和>>>的一行和===的一行删除,可以选择两个来源都保留,或者只保留一方,或者都删掉,均可。之后重新走一遍add,commit,merge,push的流程即可。(注意按顺序

  • Q3:如果我不使用代码托管平台呢?
  • A3:那么你只需要add, commit两步操作即可。
  • Q4:为什么要fetch/pull呢?
  • A4:多人协作的场景下,有可能你的同事进行了更新而你没有,那么要先同步。如果是单人的话,那么可以直接push,不需要fetch和merge进行同步。

git基础概念介绍

本地仓库

因为git还涉及其他奇奇怪怪的操作,可能会涉及各种各样的问题,因此这里先介绍一些有关git设计的基础概念。

这里借用菜鸟教程的一张图 ,画的很好:

简单来说,Git管理有两个区域:工作区(就是你能看到的目录)以及版本库(.git下面的记录),而版本库里维护了很多信息,主要包括:暂存区,目录树和对象库。其中:

  • 暂存区:暂时存放更新内容。使用add指令,会将工作区内的内容加入暂存区,更新内容会加入对象库中。而rm --cached则是add的逆过程,会将未提交的内容从暂存区移除(但工作区不受影响
  • 版本库:commit指令会将本次更新内容从暂存区加入版本库。而checkout指令会将某个版本的内容恢复到工作区中(注意:此时会清除工作区中未加入到暂存区的内容)。同时commit后,HEAD指针产生变化,移动到当前commit的内容。
  • 对象库:维护更新内容。

因此,下面简单介绍一下常用指令的用法:

  • add:将更新内容加入到暂存区中。
  • commit:将暂存区中更新的内容提交到目录树中进行维护。
  • rm --cached :从暂存区删除未提交文件,工作区则不做出改变。
  • checkout危险操作,会清除工作区未添加到暂存区的内容。
  • reset暂存区的目录树会被重写,被 master 分支指向(HEAD )的目录树所替换,但是工作区不受影响。
  • log:查看历史提交记录。

远程仓库

那么现在考虑托管平台,又该如何做呢?还是借用菜鸟教程的图

是的,与托管平台之间的交互很多,主要有git pullgit push等,这是最常见的交互方式。但如果需要push。想必之前你已经弄好了一个仓库,那么,我们试一下如下指令?

1
2
3
4
5
6
7
8
9
10
11
git remote -v 
# origin git@github.com:spiritTrance/blogPostArchive.git (fetch)
# origin git@github.com:spiritTrance/blogPostArchive.git (push)
git branch
# * master
git branch -a
# * master
# remotes/origin/master
git branch -avv
# * master 9af8fd2 [origin/master] 博客文章存档
# remotes/origin/master 9af8fd2 博客文章存档

那么这几条语句可以帮助你看到,远程仓库是git@github.com:spiritTrance/blogPostArchive.git,其别名是origin。而git branch加入-a选项后,可以同时看到本地和远程仓库的分支。对的,本地有一堆分支,远程仓库同样可以有一堆分支。使用-vv/-avv选项,可以看到分支的最后一条提交记录。值得注意的是,master一行后面的方括号,标注了对应的远程分支。因此,不难猜出,本地的一个分支和远程的一个分支其实是有对应关系的。那么我们应当如何设置这个对应关系呢?回到之前的教程,我们可以发现如下语句:

1
2
3
git branch -M main 
git remote add origin git@github.com:[你的用户名]/[你的远程仓库名].git
git push -u origin main

其中
- 第一条语句的作用是将当前分支的名称改成main
- 第二条语句的仓库是加入远程仓库git@github.com:[你的用户名]/[你的远程仓库名].git,别名为origin
- 第三条语句是关键:-u全名为--set-upstream,这个指令用来设置推送流,将本地的main分支和远程的main分支(没有则自动创建)关联起来(当然,你可以按照<localbranch>:<remotebranch>的格式指定远程分支)。之后使用git push,会默认按照这个上游分支推送。

你可以修改推送流,推送到不同的远程分支,甚至将本地仓库与多个远程仓库进行关联。
你可以将本次推送推送到不同分支:git push origin <localBranch>:<remoteBranch>,如果远程分支不存在,甚至会创建,因此又引出了另外一个议题——分支保护。这在多人协作中防铸币队友特别好用。另外,你也可以直接删除远程仓库的分支:git push <remote> --delete <branchname>.

总结一下,本小节你应该知道如下内容:

1
2
3
4
git remote add <remoteAlias> git@github.com:[你的用户名]/[你的远程仓库名].git # 使用本指令添加远程仓库,别名为remoteAlias(一般是origin)
git push --set-upstream <remoteAlias> <localBranch>:<remoteBranch> # 使用本指令设置上游分支并推送到指定仓库的指定分支
git push <remoteAlias> --delete <remoteBranch> # 删除远程指定分支

分支及版本管理

考虑到项目开发可能存在多个版本,因此git有分支模型,最常见的是maim分支和dev分支,前者是发行版本,后者是开发版本。当然,在多人协作中也更为常见。下面介绍一下git的基本原理,以及与分支管理相关的操作。

VsCode扩展 - Git Graph

Git Graph扩展可以清晰地展示git仓库的分支的历史提交信息和合并情况,因此强烈建议安装使用。

安装好后,按下ctrl+shift+p,选择Git Graph: View Git Graph,即可查看当前目录的分支信息。

checkout指令

checkout指令可以干什么呢?可以做的事情很多:(创建并)切换分支,版本回滚。但实际上,如果认真看了【分支管理】小节的菜鸟教程和HEAD的超链接的介绍,稍加思考就可以知道,checkout本身的作用就是恢复到对应的提交记录。下面在cmd中输入git checkout -help可以查看基本用法:

1
2
usage: git checkout [<options>] <branch>
or: git checkout [<options>] [<branch>] -- <file>...

其中:

<options>的作用请输入git checkout -help自行查看,其中常用的选项是-b
<branch>的作用是指定某个分支,或者记录。例如,可以选分支名master或dev或origin,可以是某次提交记录:使用git log 并找到对应的提交记录进行恢复,如某个SHA值9653625095299ae3f21ec254fc41f3588abbabba,又如HEAD(即最后一次commit的记录)或是HEAD^(HEAD指向的记录的前一条记录)。
-- <file>就是指定某个文件进行恢复。

值得提醒的是,checkout指令会覆盖到工作区的内容(也就是你当前看到的目录的内容),请务必小心使用。

下面展示新建分支并切换的用法:

首先,我们创建好一个文档后,使用add指令和commit指令,提交刚创建的文档。右边的Git Graph就显示了当前的提交记录。

此时,我们可以在命令行里面键入如下指令:

1
2
git checkout -b dev # 创建dev分支并切换到dev分支
# 这条指令相当于git branch dev; git checkout dev指令.(branch指令将在后面介绍)。

之后修改文件,再次执行add,commit 操作即可。

第二个用法是版本回滚,再次强调会覆盖工作区的内容。简单罗列下指令:

1
2
git checkout .    # 【工作区】的内容回滚到最后一次提交的内容
git checkout HEAD . # 同上

另外稍微提醒一下,HEAD的变化在切换分支的时候也会发生。

branch指令

1
2
3
git branch       # 罗列所有分支
git branch bName # 创建一个名为bName的分支,后续通过checkout指令切换
git branch -d bName # 删除一个名为bName的分支

merge指令

merge的用途在于合并分支。现在我有master分支和dev分支,其中dev分支由master的基础上创建出来,其中master有README.md文件,dev分支有README.md文件。此时如果在master分支创建test1.txt文件,dev分支创建test2.txt文件,那么在master分支merge的时候,两个文件都会合并进入master分支。

1
2
git merge dev     # 在master分支上,将dev分支合并进来
git branch -d dev # 删除dev分支

但如果在创建分支后,在两个分支上都对同一个文件进行了修改,那么对应文件会标出冲突部分,按照提示修改,然后重新addcommitmerge即可。

rebase指令

(待补)

rebase与merge谁更好?(见评论区)

评论区高度赞同的回答——关于rebase和merge的比较

reset指令

用途:回退版本,取消缓存区的内容,参考教程

tag指令

使用场景:到达一个重要阶段使用。使用参考

stash指令

使用场景:你正在dev分支工作,然后突然告知release分支出现问题需要马上修复,然而你dev上已经做了修改但还不能commit,此时你希望能先暂存你的进度,那么可以考虑stash指令。使用参考

cherry-pick

远程仓库操作

远程仓库与本地仓库管理区别在哪?

图片参考
https://www.runoob.com/w3cnote/git-guide.html

pull,push与fetch指令

进阶内容

钩子函数

钩子函数的位置在.git/hooks下面,钩子函数是一个特别强大的工具,可以帮助你在进行对应操作之前进行检查,如大文件提交问题可以通过设置钩子函数解决。

创建.git/hooks/pre-commit,在里面写入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/sh
# pre-commit hook checking for files larger than 100MB

# Set the file size limit
LIMIT=$((100 * 2**20)) # 100MB in bytes
isFlag=0

# Check staged files
git diff --cached --name-only -z | while IFS= read -r -d '' FILE; do
# echo "Checking file: $FILE"
if [ -f "$FILE" ] && [ "$(wc -c <"$FILE")" -gt "$LIMIT" ]; then
if [ "$isFlag" -eq 0 ]; then
echo -e "\n# [Warn] At $(date +"%Y-%m-%d %H:%M:%S"): Big size file founded (more than 100MB). They are unstaged and recorded in \`.gitignore\`." >> .gitignore
isFlag=1
fi
echo "Warning: File $FILE is larger than 100MB, it is removed from staged area"
git reset "$FILE"
echo "$FILE" >> .gitignore
fi
done

即可在git commit操作时执行pre-commit脚本。其他函数详见.git/hooks/*.sample里面的注释。

常见操作记录

内建图形化界面-gitk

在有git仓库的项目下,在bash中输入gitk即可进入图形化界面。

疑难杂症记录

footprint更改

大文件的提交

  • 注意github不允许单个文件超过100MB的文件提交,所以请设置好 .gitignore文件

  • 如果不慎提交大文件,一个解决方法使用Git lfs(还不会,貌似要收费,不推荐),另外一个是将大文件的提交记录从本地删除,再重新提交,具体操作步骤如下:

    1
    2
    git log
    git reset <hashcode>

    其中git log 是查看历史提交记录(所以git commit填写的内容十分重要!!),查看后,使用git reset逐步取消提交记录,直到提交大文件的那次记录的前一条记录(包含前一条),之后重新add,commit,push即可

detached HEAD

在学习checkout的时候,不小心整出了这样一个状态:

Note: switching to 'HEAD^'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

git switch -c

Or undo this operation with:

git switch -

Turn off this advice by setting config variable advice.detachedHead to false

原因分析:输入git checkout HEAD^即可复现,原因未知。git checkout HEAD^ .就不会出现这个状况,指定下文件?
恢复方法:输入git branch可以查看分支,然后当前分支是detached xxxx,然后可以在该游离的“分支”上使用git merge合并分支,以保证提交不会被gc 掉。

扩展阅读


  1. github简明资料 ↩︎

  2. git提交push过滤规则.gitignore(本文为CSDN博主「HKYAOYAOLING」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。) ↩︎

  • Title: git快速入门
  • Author: spiritTrance
  • Created at: 2022-07-18 00:05:11
  • Updated at: 2024-02-07 20:59:37
  • Link: https://spirittrance.github.io/2022/07/18/git_gitStarter/
  • License: This work is licensed under CC BY-NC-SA 4.0.
推荐阅读
Hexo快速入门 Hexo快速入门 linux基本操作学习 linux基本操作学习 【MIT6.172】学习笔记(1) 【MIT6.172】学习笔记(1)
 Comments