Git(四)

2021-05-12  本文已影响0人  浅墨入画

一. Git Hook

image.png image.png

第一张图中的pre-commit post-commit对应hooks目录里面的.sample脚本文件
打开pre-commit.sample脚本文件,输出下面一句内容

image.png

去掉.sample后缀名

image.png
// 打开LGTeacherModel.swift文件,修改内容如下
extension LGTeacher {
    static var all: [LGTeacher] {
        [
            LGTeacher( name: "Cooci" ),
            LGTeacher( name: "Kody" ),
            LGTeacher( name: "Hank" ),
            LGTeacher( name: "CC" ),
            LGTeacher( name: "Cat1237" )(修改前) -> LGTeacher( name: "Cat" )(修改后)
        ]
    }
}

$ cd /Users/wn/Documents/资料/git-hook/01-LGClass-Start
// 从下面打印就可以看出,git hook 执行的确实是hooks目录下对应的脚本文件
$ git commit -am '修改了Cat'
Cat1237—— 
[master ae87b35] 修改了Cat
 1  file  changed,1  insertion(+),1  deletion(-) 

接下来我们修改hooks目录下的pre-commit文件为pre-commit.sample,并且修改其内容如下,修改完成之后继续把pre-commit.sample去掉后缀改成pre-commit

// pre-commit.sample文件内容
#!/usr/bin/env python 
print("Cat1237---py") 

// 打开LGTeacherModel.swift文件,修改内容如下
extension LGTeacher {
    static var all: [LGTeacher] {
        [
            LGTeacher( name: "Cooci" ),
            LGTeacher( name: "Kody" ),
            LGTeacher( name: "Hank" ),
            LGTeacher( name: "CC" ),
            LGTeacher( name: "Cat" )(修改前) -> LGTeacher( name: "Cat123" )(修改后)
        ]
    }
}

$ git commit -am '修改了Cat'
Cat1237---py
[master 1299a75] 修改了Cat
 1  file  changed,1  insertion(+),1  deletion(-) 
小结

git hook目录里面即可以执行shell脚本,也可以执行pytho脚本

二. Git Reflog

Git Reflog 用来记录git的所有操作过程

// 打开LGTeacherModel.swift文件,修改内容如下
extension LGTeacher {
    static var all: [LGTeacher] {
        [
            LGTeacher( name: "金牌讲师-Cooci" ),
            LGTeacher( name: "布加迪Kody" ),(修改前) -> LGTeacher( name: "Kody" ),(修改后)
            LGTeacher( name: "钻石讲师-Hank" ),
            LGTeacher( name: "CC" ),
            LGTeacher( name: "Cat" )
        ]
    }
}

$ cd /Users/wn/Documents/资料/Reflog/01-LGClass
$ git commit -am '修改了Kody'
[cKody 8b8a345] 修改了Kody
 1 file changed, 1 insertion(+), 1 deletion(-)
// 查看之前所有的git操作
$ git reflog
8b8a345 (HEAD -> cKody) HEAD@{0}: commit: 修改了Kody
0169c5e HEAD@{1}: checkout: moving from 0169c5e58c694b2f5050df7fa1c2883ac4c5c40b to cKody
0169c5e HEAD@{2}: checkout: moving from kTeacherListView to HEAD@{1}
a1cef39 (kTeacherListView) HEAD@{3}: reset: moving to ORIG_HEAD
0169c5e HEAD@{4}: commit: 修改了Kody
f8ccf83 HEAD@{5}: checkout: moving from hPopAnimator to kTeacherListView
46fd8c8 (hPopAnimator) HEAD@{6}: checkout: moving from cPopAnimator to hPopAnimator
...
$ git reflog --help
 git-reflog - Manage reflog information  //管理回滚信息
// 回退到之前commit状态
$ git reset --hard ORIG_HEAD
HEAD is now at 0169c5e 修改了Kody
// 再次查看记录信息
$ git reflog
0169c5e (HEAD -> cKody) HEAD@{0}: reset: moving to ORIG_HEAD
8b8a345 HEAD@{1}: commit: 修改了Kody
0169c5e (HEAD -> cKody) HEAD@{2}: checkout: moving from 0169c5e58c694b2f5050df7fa1c2883ac4c5c40b to cKody
0169c5e (HEAD -> cKody) HEAD@{3}: checkout: moving from kTeacherListView to HEAD@{1}
a1cef39 (kTeacherListView) HEAD@{4}: reset: moving to ORIG_HEAD
0169c5e (HEAD -> cKody) HEAD@{5}: commit: 修改了Kody
f8ccf83 HEAD@{6}: checkout: moving from hPopAnimator to kTeacherListView
46fd8c8 (hPopAnimator) HEAD@{7}: checkout: moving from cPopAnimator to hPopAnimator
...
// 现在想回到8b8a345 HEAD@{1}: commit: 修改了Kody状态,该怎么操作?可以使用git checkout 
// git checkout 可以切换分支,也可以根据commit_ID回到某一次提交状态
$ git checkout HEAD@{1}
Note: switching to 'HEAD@{1}'.
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 <new-branch-name>
Or undo this operation with:
  git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 8b8a345 修改了Kody
image.png

上图中可以看出kTeacherListView分支仍然是上一次提交的状态,现在要怎么把commit真正的恢复出来?

$ git checkout -b cKody
Switched to a new branch 'cKody'

上面通过创建新的分支,在cKody分支上恢复到之前的commit,现在就可以使用git rebase等操作合并到一个分支上

三. Git Revert

git revert 在现有HEAD基础上创建commit,回到之前想要恢复的状态,这样就能保证远程的分支上不会出现错误

$ cd /Users/wn/Documents/资料/Revert/初始化代码/Hank
// 查看远程仓库
$ git remote
origin
$ git remote -v
origin  ../Remote.git (fetch)
origin  ../Remote.git (push)
// 查看当前所在分支
$ git branch
* hLogic
  master
// 查看当前分支commit记录
$ git log --oneline --decorate --graph --stat
* e67cb7d (HEAD -> hLogic, origin/master, master) init project

// 修改ViewController.swift内容如下
import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print("Hello Cat!")(修改前) -> print("Hello Cat1237---!")(修改后)
    }
}

$ git commit -am '修改了Cat'
[hLogic 1fc0ce4] 修改了Cat
 1 file changed, 1 insertion(+), 1 deletion(-)
// 此时commit记录中有两次commit
$ git log --oneline --decorate --graph --stat
* 1fc0ce4 (HEAD -> hLogic) 修改了Cat
|  LGClass/LGClass/ViewController.swift | 2 +-
|  1 file changed, 1 insertion(+), 1 deletion(-)
* e67cb7d (origin/master, master) init project
...
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ git merge hLogin
Fast-forward
... 
// hLogin分支直接合并到master分支上
$ git log --oneline --decorate --graph --stat
* e67cb7d (HEAD -> master, hLogin) 修改了Cat
// push到远程仓库
$ git push
// 还原到之前状态
$ git revert HEAD --no-edit
[master 25cac22] Revert “修改了Cat”
Date: Sun May 9 22:14:20 2021 +0800
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline --decorate --graph --stat
* 9c5232f (HEAD -> master) Revert "init project"

// ViewController.swift内容成功恢复
import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print("Hello Cat!")
    }
}
commit记录.png

四. Git Rebase

下面探讨git rebase为什么是把一个分支添加到另一个分支的结尾?
$ cd /Users/wn/Documents/资料/Rebase/初始代码/01-Rebase使用/01-LGClass
$ git branch
  cPopAnimator
  hPopAnimator
* kTeacherListView
  master
$ git checkout -b kTeacherImage
Switched to a new branch 'kTeacherImage'

// 修改LGTeacherModel.swift文件内容如下
extension LGTeacher {
    static var all: [LGTeacher] {
        [
            LGTeacher( name: "金牌讲师-Cooci" ),
            LGTeacher( name: "Kody" ),(修改前) -> LGTeacher( name: "布加迪-Kody" ),(修改后)
            LGTeacher( name: "钻石讲师-Hank" ),
            LGTeacher( name: "CC" ),
            LGTeacher( name: "Cat" )
        ]
    }
}

$ git commit -am '修改Kody->布加迪Kody'
[kTeacherImage 92a7e32] 修改Kody->布加迪Kody
 1 file changed, 1 insertion(+), 1 deletion(-)

// 切换到kTeacherListView分支进行修改
$ git checkout kTeacherListView
Switched to branch 'kTeacherListView'

// 修改LGTeacherModel.swift文件内容如下
extension LGTeacher {
    static var all: [LGTeacher] {
        [
            LGTeacher( name: "金牌讲师-Cooci" ),
            LGTeacher( name: "Kody" ),
            LGTeacher( name: "钻石讲师-Hank" ),
            LGTeacher( name: "CC" ),(修改前) -> LGTeacher( name: "美丽的-CC" ),(修改后)
            LGTeacher( name: "Cat" )
        ]
    }
}

$ git commit -am '修改CC-美丽的CC'
[kTeacherListView cfb1a9e] 修改CC-美丽的CC
 1 file changed, 1 insertion(+), 1 deletion(-)
git merge.png git rebase.png

上面两个分支都有提交,此时有两种合并方式分别如上图

$ git rebase kTeacherListView
Switched to branch 'kTeacherListView'
$ git rebase kTeacherImage
First, rewinding head to replay your work on top of it...
Applying: 修改CC-美丽的CC
Using index info to reconstruct a base tree...
M   LGClass/LGTeacherModel.swift
Falling back to patching base and 3-way merge...
Auto-merging LGClass/LGTeacherModel.swift
$ git branch -d kTeacherImage
Deleted branch kTeacherImage (was 92a7e32).
// 查看commit记录,成功合并到一个分支
$ git log --oneline --decorate --graph --stat
* f012e62 (HEAD -> kTeacherListView) 修改CC-美丽的CC
|  LGClass/LGTeacherModel.swift | 2 +-
|  1 file changed, 1 insertion(+), 1 deletion(-)
* 92a7e32 (kTeacherImage) 修改Kody->布加迪Kody
|  LGClass/LGTeacherModel.swift | 2 +-
|  1 file changed, 1 insertion(+), 1 deletion(-)
* f8ccf83 修改Hank-> 钻石讲师Hank
|  LGClass/LGTeacherModel.swift | 2 +-
|  1 file changed, 1 insertion(+), 1 deletion(-)
... 
探讨git rebase解决分支冲突?
$ cd /Users/wn/Documents/资料/Rebase/初始代码/02-Rebase合并分支/02-LGClass-Start
$ git branch
  cPopAnimator
* hPopAnimator
  kTeacherListView
  master
// 查看某一个commit点到分支HEAD的提交记录
$ git log --oneline fa1278f~..
46fd8c8 (HEAD -> hPopAnimator) 添加popAnimator for dismiss实现
9b4e62c 添加popAnimator for presented实现
fa1278f 添加UIViewControllerTransitioningDelegate for popAnimator
// 指定到某一个分支,查看某一个commit点到分支HEAD的提交记录
$ git log --oneline fa1278f~..hPopAnimator
46fd8c8 (HEAD -> hPopAnimator) 添加popAnimator for dismiss实现
9b4e62c 添加popAnimator for presented实现
fa1278f 添加UIViewControllerTransitioningDelegate for popAnimator
// 产生冲突
$ git rebase cPopAnimator
First, rewinding head to replay your work on top of it...
Applying: 添加popAnimator for presented实现
Using index info to reconstruct a base tree...
M   LGClass/ViewController.swift
Falling back to patching base and 3-way merge...
Auto-merging LGClass/ViewController.swift
CONFLICT (content): Merge conflict in LGClass/ViewController.swift
error: Failed to merge in the changes.
Patch failed at 0001 添加popAnimator for presented实现
hint: 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".

// ViewController.swift文件产生冲突
extension ViewController: UIViewControllerTransitioningDelegate {
  func animationController(
    forPresented _: UIViewController, presenting _: UIViewController, source _: UIViewController
  ) -> UIViewControllerAnimatedTransitioning? {
<<<<<<< HEAD
      // 添加popAnimator到当前的ViewController,同时指定动画方式
      selectedImage.alpha = 0
      popAnimator.presenting = true
      let frame = selectedImage.superview!.convert(selectedImage.frame, to: nil)
      popAnimator.originFrame = frame
      return popAnimator

=======
    selectedImage.alpha = 0
    popAnimator.originFrame = selectedImage.superview!.convert(selectedImage.frame, to: nil)
    popAnimator.presenting = true
    return popAnimator
>>>>>>> 添加popAnimator for presented实现
  }

// 停止当前rebase,回退到冲突前
$ git rebase --abort
// 指定产生冲突类型
$ git config merge.conflictstyle diff3
// 冲突类型修改
$ git rebase cPopAnimator

extension ViewController: UIViewControllerTransitioningDelegate {
  func animationController(
    forPresented _: UIViewController, presenting _: UIViewController, source _: UIViewController
  ) -> UIViewControllerAnimatedTransitioning? {
<<<<<<< HEAD
      // 添加popAnimator到当前的ViewController,同时指定动画方式
      selectedImage.alpha = 0
      popAnimator.presenting = true
      let frame = selectedImage.superview!.convert(selectedImage.frame, to: nil)
      popAnimator.originFrame = frame
      return popAnimator

||||||| constructed merge base
    nil
=======
    selectedImage.alpha = 0
    popAnimator.originFrame = selectedImage.superview!.convert(selectedImage.frame, to: nil)
    popAnimator.presenting = true
    return popAnimator
>>>>>>> 添加popAnimator for presented实现
  }

// 可以手动解决冲突,也可以使用git mergetool解决
$ git mergetool
// 解决完冲突之后,添加代码到暂存区
$ git add .
// 继续执行rebase,又一次报了冲突
$ git rebase --continue
Applying: 添加popAnimator for presented实现
Applying: 添加popAnimator for dismiss实现
Using index info to reconstruct a base tree...
M   LGClass/ViewController.swift
Falling back to patching base and 3-way merge...
Auto-merging LGClass/ViewController.swift
CONFLICT (content): Merge conflict in LGClass/ViewController.swift
error: Failed to merge in the changes.
Patch failed at 0002 添加popAnimator for dismiss实现
hint: 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".
// 将引起冲突的commits丢弃掉
$ git rebase --skip
// 继续执行rebase,成功解决上面分支冲突
$ git rebase --continue
fatal: No rebase in progress?
$ git add .
小结
探讨git rebase重写提交历史?
$ cd /Users/wn/Documents/资料/Rebase/初始代码/03-Rebase处理提交历史/03-LGClass-Start
// 查看分支提交记录
$ git log --all --decorate --oneline --graph
* f8ccf83 (HEAD -> kTeacherListView) 修改Hank-> 钻石讲师Hank
* 28e389f 修改Cooci-> 金牌讲师Cooci
* ec310cf 添加讲师图片
* 06a3d23 添加teacherDetails dismiss TapGestureRecognizer
* 8d6c4ff 添加teacherDetails.transitioningDelegate
* 3842ea1 present TeacherDetailViewController
* ad9de28 给点击照片添加TapGestureRecognizer
* 66f37fe 在stackView上展示讲师照片
* f00b12e 创建TapGestureRecognizer
...
// 查看ec310cf提交历史,并对其进行修改
$ git rebase -i ec310cf
// pick表示选择了这个commit
pick 28e389f 修改Cooci-> 金牌讲师Cooci(修改前) -> pick 28e389f 修改Cooci-> 金牌讲师Cooci,Cooci牛(修改后)
pick f8ccf83 修改Hank-> 钻石讲师Hank
// 从ec310cf提交点开始,上面一共有两个commit,可以对这两个commit  pick选择之后修改
# Rebase ec310cf..f8ccf83 onto ec310cf (2 commands)
#
# Commands:
# p, pick <commit> = use commit
...
// 再次查看分支提交记录,发现上面的修改并没有成功,因为刚才使用的pick,只是选择了某个commit,并没有进行编辑
$ git log --all --decorate --oneline --graph
* f8ccf83 (HEAD -> kTeacherListView) 修改Hank-> 钻石讲师Hank
* 28e389f 修改Cooci-> 金牌讲师Cooci
* ec310cf 添加讲师图片
...
// 这次试用e进行编辑
$ git rebase -i ec310cf
e 28e389f 修改Cooci-> 金牌讲师Cooci牛
pick f8ccf83 修改Hank-> 钻石讲师Hank

# Rebase ec310cf..f8ccf83 onto ec310cf (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
... 

Stopped at 28e389f...  修改Cooci-> 金牌讲师Cooci牛
You can amend the commit now, with

  git commit --amend

Once you are satisfied with your changes, run

  git rebase --continue
// 按照上面提示执行 git commit --amend
$ git commit --amend
修改Cooci-> 金牌讲师Cooci(修改前) -> 修改Cooci-> 金牌讲师Cooci牛(修改后)
...
// 成功修改
$ git rebase --continue
Successfully rebased and updated refs/heads/kTeacherListView.
// 查看提交历史,发现成功修改
$ git rebase -i ec310cf
pick 4f6c4f3 修改Cooci-> 金牌讲师Cooci牛
pick 74ba881 修改Hank-> 钻石讲师Hank

# Rebase ec310cf..74ba881 onto ec310cf (2 commands)
#
...
// 这一次我们使用squash 压缩几个commit成一个commit,下面修改完成 wq保存并退出
squash 4f6c4f3 修改Cooci-> 金牌讲师Cooci牛
squash 74ba881 修改Hank-> 钻石讲师Hank

// 报了下面的错误
error: cannot 'squash' without a previous commit
You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
Or you can abort the rebase with 'git rebase --abort'.
// 上面报错,终止当前rebase
$ git rebase --abort

$ git rebase -i ec310cf
// 第一步修改并保存
pick 4f6c4f3 修改Cooci-> 金牌讲师Cooci牛
s 74ba881 修改Hank-> 钻石讲师Hank
// 第二步修改并保存
# This is a combination of 2 commits.
# This is the 1st commit message:

修改Cooci-> 金牌讲师Cooci牛(修改前) -> 修改Hank-> 钻石讲师Hank,修改Cooci-> 金牌讲师Cooci牛(修改后)

# This is the commit message #2

// 再次提示修改成功,我们发现两个commit进行了合并
Successfully rebased and updated refs/heads/kTeacherListView.

// 下面我们来进行移除commit
$ git rebase -i ec310cf
// 这里使用d移除上面合并的commit,保存并退出,成功移除
d 3406b2b 修改Hank-> 钻石讲师Hank,修改Cooci-> 金牌讲师Cooci牛
...

上面使用e, edit <commit> = use commit, but stop for amending修改提交记录时,在执行git commit --amend之前,也可以创建文件并执行git add .添加到暂存区,再执行git commit --amend,这时会让再次修改提交记录信息,修改并保存。最后执行git rebase --continue,会发现历史记录成功修改并添加了刚才新创建的文件。

上一篇下一篇

猜你喜欢

热点阅读