======Git & GitHub======
Git / GitHub Notes\\
----
====Git====
===基础流程与相关命令===
Git 分为三个区域:**工作区**,**暂存区**,**版本库**:
* 工作区(//Working area//):进行工作的区域,比如建立,编辑,分类文件等
* 暂存区(//Staging area//):存放修改过的文件
* 版本库(//Repository//):存储当前软件的某个正式版本
==工作流程==
Git 的基本工作流程是,在工作区创建好文件,然后将文件提交到暂存区;确认无误后将改动提交到版本库,作为新的版本发布:
\\ \\
{{ :software_dev:ver_ctrl:git_basic_workflow.svg?500 |}}
\\ \\
==相关命令==
* **git init**:将当前的文件夹转化为 git 项目文件夹
* **git status**:查看当前文件夹的中文件的状态
* **git add**:将**工作区**的文件添加到**暂存区**
* **git diff**:查看指定文件在**工作区与暂存区**之间的不同
* **git commit**:将**暂存区**的文件提交至**版本库**
* **git log**:查看 commit 的历史
* **git rm**:将文件删除并移除出版本库
==git diff==
打印信息的例子:
#git diff output example
#white, nothing changed, indicated in white
* @Author: Codinghare
* @Date: 2022-05-22 21:42:56
* @Last Modified by: hare
#start with "-", removed or replaced, indicated in red
- * @Last Modified time: 2022-05-30 00:16:57
#start with "+", changes to the file, indicated in green.
+ * @Last Modified time: 2022-05-30 00:42:45
退出使用按键 ''q'' 即可。\\
\\
查看某个文件工作区与最新版本的区别:
git diff HEAD -- file
==git commit==
git commit 有一个非常好用的 tag ''amend''。这个 tag 允许我们对当前最新的 commit 的进行更新,而不是创建一个新的 commit。这个命令在修改当前 commit 中的一些**细小错误**时非常有用。
\\ \\
当然,虽然看上去是”更新“了 commit,''amand'' 实际上还是创建了一个新的 commit,并取代了旧的 commit(只是不会有新的 commit)记录。但终端会弹出界面要求我们重新书写 comment(''-m'' 里写的东西)。如果要维持之前的 comment,使用下面的命令:
git commit --amend --no-edit
==git log==
打印信息的例子:
#SHA, unique id for the commit
commit 5f9c857051c2a9acc2036e90b4c965e16798bd6b
#Author
Author: hare
#Date
Date: Thu Jun 2 23:14:49 2022 -0600
#comments, generated by git commit -m " "
fixed typos.
一些相关的 tag:
git log --online #shows the list of commits in one line format.
git log -S "keyword" #displays a list of commits that contain the keyword in the message.
git log --oneline --graph #Displays a visual representation of how the branches and commits
==git rm==
直接删除版本库文件夹下的文件并不能将其移除出版本库。查看会显示该文件的状态是被删除:
On branch master
Changes not staged for commit:
(use "git add/rm ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
deleted: test.txt
* 如果要删除记录,则应该使用 ''git rm '',然后做 ''git commit''
* 如果要回复记录(当前最近版本):则使用 ''git restore ''
===Backtracking===
BackTracking 的主要内容:
* 将不符合要求的文件移除暂存区
* 将工作区中被错误修改的文件回滚到未修改之前的状态
* 将当前的 commit 回滚到之前某次的 commit
关键的概念:
* 当前最新的 commit 被成为 HEAD commit.
* ''reset'' 命令会更改当前的 HEAD commit 到指定的 commit
==相关命令==
* **git show HEAD**:查看当前最新的 commit 的信息。信息额外包括了文件的变动信息。
* **git checkout HEAD**:**取消** HEAD commit 做出的改动。
* **git checkout - -**:上面命令的简化版本。
* **git reset**:将已经提交到 staging 区域中的某个文件**移除**。
* **git reset commit_SHA**:将 staging 区域中的文件**重置**为与 指定 SHA commit 中一致,也就是重新指定当前的 Head。commit_SHA 是 commit SHA 的 **头7** 位。重新指定当前 HEAD 之后,该 HEAD 之后的所有改动都会消失。
* **git stash**:将当前未完成的工作赞存入一个临时区域(临时区域可拥有多个)
* **git stash pop**:取回临时区域的内容
==git reset / checkout==
* ''git reset'' 通常用于暂存区中存在着不符合要求文件的情况。比如不小心将错误的源文件送至暂存区后,可以使用 reset 命令将其移除出暂存区。
* ''git reset + SHA'' 使得对应的 commit 会成为当前的 HEAD commit。该 commit 之后的所有内容将不再成为项目的一部分。
* ''git checkout'' 则是对**工作区**的文件进行还原。当不小心修改了工作区中的文件时,可以利用该命令将其还原到 HEAD commit 时文件的状态,也就是没有被修改前的状态。
* 新版本中,''git restore'' 替换了 ''git checkout'' 和 ''git reset'' 的部分功能:
# revert the file that has not been added to the staging area.
# git checkout --
git restore
# moving the file that has been added to the staging area back to the working driectory
# git reset file
git restore --staged
==git stash==
这个命令主要用于保存当前未完成的工作。比如当我们正在进行工作 A(brach A),然后接到要求去 B(branch B)进行另外工作的要求。此时我们就可以使用 ''git stash'' 将 A 这边的工作暂存;当完成 B 的工作后,回到 A,使用 ''git stash pop'' 就可以将之前未完成的工作取回,接着进行工作了。
\\ \\
这个命令避免了将未完成的文件进行 commit 的情形。该临时暂存的档案可以建立多个,可以通过 ''git stash --list'' 查看。
# saving the WIP
git stash
# revert the WIP but keep the saving
git stash apply
# delete the save file
git stash drop
# revert the WIP and delete the save file
git stash pop
===temp===
* **git alias**:使用该命令可以对 git 当前命令进行 alias,允许我们使用更短的命令代替原有的命令:
$ git config --global alias.co "checkout"
$ git config --global alias.br "branch"
$ git config --global alias.glop "log --pretty=format:"%h %s" --graph"
===初始设置===
==设置用户名和 email==
#define global user name for the local repo
git config --global user.name "xxxx"
#define email for the local repo
#must match the github user email
git config --global user.email "your@email.com"
==链接到 github==
* 在 github 上手动建立一个 repo
* 链接本地 repo 和 github repo
git remote add origin https://repo.address
git push -u origin master
#check if the repo linked
git remote -v
===Branching===
Git 允许创建不同的 branch 来对项目进行实验;也就是说,新的 branch 是作为之前版本的改动而存在的;我们可以在新的 branch 中进行开发和实验,直到功能稳定之后再合并到主要版本中,再作为新的项目版本进行发布。新的 branch 包括两部分:
* 之前 master branch 的内容(所有 commit)
* 新 branch 自身拥有的内容
==相关命令==
* **git branch**:查看当前所在的 branch。
* **git branch new_branch**:建立名为 ''new_branch'' 的新 branch。
* **git branch -d branch_name**:删除名为 ''branch_name'' 的 branch
* **git branch -D branch_name**:功能同上。如果被删除的 branch 从未合并到 master,需要使用 ''-D'' tag
* **git checkout branch_name**:切换到名为 ''branch_name'' 的 branch
* **git merge branch_name**:合并名为 ''branch_name'' 的 branch 到 master
# create a new branch
git branch
# create and switch to a new branch
git switch -c
# list all branchs
git branch
# switch to a branch
# old school: git checkout
git switch
==merge conflict==
合并 branch 到 master 的前提是,master 在 branch 新建之后没有发生改变。如果改变发生,之后再将 branch 合并回 master,会造成合并冲突(//merge conflict//)。这种冲突是因为 master 的不一致导致的。\\ \\
当冲突发生的时候,会产生如下的信息:
Auto-merging conflict_file_name
CONFLICT (content): Merge conflict in conflict_file_name
Automatic merge failed; fix conflicts and then commit the result.
之后我们再打开冲突发生的文件,会有如下的内容:
#master version
<<<<<<< HEAD
-content of master version
=======
#branch version
-content of branch version
>>>>>>> branch
-------------------
这一段代表了当前 ''master'' 与 ''branch'' 开始时的 ''master'' 中的内容差异。我们可以选择保留当前的 ''master'' 的修改,或是保留 ''branch'' 中对应的 ''master'' 内容。但无论如何,除了要保留的内容以外,其他所有内容(包括 git 自动产生的标记)都需要删除。
===Tagging===
git 中可以对指定的分支做 tag:
# switch to the branch before tagging
git tag
# listing exsiting tag
git tag
#deleting tag
git tag -d
#deleting tag on origin
git tag -d
git push origin :refs/tags/
默认的 tag 是关联到当前分支的**最新** commit 上的。如果希望对指定的 commit 打 tag (比如忘记打了),需要加上 commit id:
git tag
# creating tag with extra message
git tag -m "your message here"
打好 tag 以后就可以很方便根据 tag 查看 commit 了:
git show
tag 默认存在本地。如果要推送到远程,使用以下命令:
git push origin
#push all tags at once
git push origin --tags
===Teamwork===
在多人使用 git 进行合作中,一般会需要:
* 项目在本地的拷贝
* track and review 其他人工作内容的手段
* 对项目最终版本的访问权限
所有这些内容都可以通过 //Remotes// 来实现。//remotes// 允许多个合作者(可以处于不同地方)进行同一个项目的开发。每个人都可以独立在自己的内容上工作,然后最终合并到一起。
==工作流程==
- 从 //remote// 获取(//fetch// 和 //merge//)最新的项目内容
- 在本地建立新的分支进行新内容开发
- 提交新内容到本地分支
- 再次从 //remote// 获取最新的内容,确保不会错过在本地工作期间其他人提交的新内容
- //push// 本地内容到 //origin//
==相关命令==
# find the remote on remote_location and clone the your directiory called clone_name
# remote_location could be a website, or file path
git clone remote_location clone_name
#list all remotes
git remote - v
#updates the local copy
git fetch
#merge changes in the origin to the local copy
git merge origin/master
#push your branch feature to the remote
git push origin your_branch_name
#fetch and merge the newest master
git pull origin master
==git rebase==
我们在 push 的时候,如果 origin 对应分支已经发生了改变(别人提交过了),那么需要用 fetch/merge 或是 pull 来同步 origin 中的新内容到本地分支。但这样做的问题在于,我们在本地的 commits 实际上处于 pull commit 之后了,那么从路径上来说我们的 commit 之于 master 的新内容之前。这样顺序是不对的。
\\ \\
''git rebase'' 会将本地 commit 的提交历史止于 pull(origin 内容更新之后),等于重新顺理了一遍提交顺序。这样看使提交历史起来更加直观。
# before
|\
| * d662d56 (origin/master) Update readme.md.txt
* | 30bcffe modified hello2.py
* | 9091cc7 add hello2.py
|/
# after git rebase
* 280680e (HEAD -> master) modified hello2.py
* 8337019 add hello2.py
* d662d56 (origin/master) Update readme.md.txt
#after push
* 280680e (HEAD -> master, origin/master) modified hello2.py
* 8337019 add hello2.py
* d662d56 Update readme.md.txt
==git clone==
//clone// 命令是将指定的共享项目拷贝到本地的项目中。当共享项目被拷贝后,git 会自动将其与 ''origin'' 关联。
==git remote ==
# list all origins
git remove -v
# add origin
git remote add origin
# remove origin (link)
git remote rm origin
==git fetch==
如果本地版本没有及时更新(本地使用的版本已经在 origin 中被别人更新),可以使用 //fetch// 命令更新本地版本到最新。这个更新指的是信息的更新。用户在查看更新后可以自行决定是否合并 origin 的新内容到本地的对应 branch 中。
==git merge origin/master==
//fetch// 只会从 origin 下载 objects。这些 object 会存储在 ''origin/branch_name'' 中等待被合并。如果希望应用所有 origin 的新内容到本地,需要使用 //merge// 命令;也就是将 ''origin/branch_name'' 中的内容转移到 ''branch_name'' 中。
==git push==
//push// 命令允许我们将本地完成的内容推送到 //origin// 中。
# first time push
# -u: push the new data and link the local branch to the cloud branch
git push -u origin master
===Tips===
==误回滚回复==
如果知道想回滚版本的 hash:
git reset --hard hash
如果不知道:
#find the hash
git reflog
#backtrack
git reset --hard hash
==将 master 上修复的 bug 同步合并到 dev 上==
这种情况一般出现在:
* 你正在开发新的东西
* 当前的 master 分支出现了 Bug 并被修复了
这种情况下,无需去 dev 分支上再把 bug 修改一遍,只需在 dev 分支上使用如下命令即可合并 Bug 修复内容到 dev:
git cherry-pick
====Git Hub====
===GitHub 的简单工作流程===
- 建立 新的 branch
- commit
- 建立 pull request
- 等待 reviewer 的审查通过
- 合并当前 branch 到 master branch,并删除当前 branch
{{ :software_dev:ver_ctrl:github_flow.svg?500 |}} \\ \\
==新建 branch 的必要性==
* 防止冲突
* 保证主项目(master branch)不受开发进程的影响
==branch 的命名方式==
#author + branch type + short branch description
hare_feature_dashboard_notifications
==pull request 的注意事项==
* 提供足够的细节以便节省 review 的时间
* PR 较小的更新,让 review 更快更容易
==review 的注意事项==
* comment 应该包括需要修改的内容和原因
* 清晰的表达自身的意思
* 指出潜在的问题
===添加 github 远程仓库===
首先查找用户主目录下有没有 ''id_rsa'' 和 ''id_rsa.pub'' 的文件,如果没有,使用以下命令生成 ''key''(命令中的邮箱使用自己的邮箱):
ssh-keygen -t rsa -C "youremail@xxxmail.com"
运行以上命令后访问 ''.ssh'' 目录,会找到 ''id_rsa'' 与 ''id_rsa.pub'' 两个文件,前者是私有密钥,需要妥善保存;后者是公有密钥,可以放心告诉别人。
\\
\\
接下来到 Github 中的 ''seting'' 中找到 ''SSH and GPG keys'',将刚才生成的 ''id_rsa.pub'' 中的内容作为一个新的 SSH key 添加到 GitHub中。
\\
\\
添加完成之后可以输入如下命令测试是否连接成功:
ssh -T git@github.com
如果显示以下文本就证明连接成功了:
Hi XXXX! You've successfully authenticated, but GitHub does not provide shell access.
到此就可以使用 git 命令对远程库操作了。
===Trouble shooting===
==GitHub Error Message - Permission denied (publickey)==
**可能的解决方案**:
----
* 不使用 ''sudo'' 进行 Git 命令的使用
----
* 如果出现以下错误:
Git XXX: fatal: could not set 'core.filemode' to 'false'
尝试修改 ''/etc/wsl.conf'',添加以下代码(没有则创建):
[automount]
options = "metadata"
之后运行:
wsl --shutdown
重启即可
----
* 如果是多用户,并出现以下错误:
fatal: Could not read from remote repository.
尝试将密钥文件夹复制给 root 一份:
sudo cp ~/.ssh/* /root/.ssh/
==让 git 忽略文件权限改变带来的改动==
git config core.filemode false
====References====
* [[https://education.github.com/git-cheat-sheet-education.pdf|cheatsheet]]
* [[https://www.liaoxuefeng.com/wiki/896043488029600/900005860592480|廖雪峰的官方网站]]