======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|廖雪峰的官方网站]]