简体   繁体   English

Git工作流来审核提交而无需重写历史记录

[英]Git workflow to audit commits without rewriting history

I am working with a developer that is new to git, and I would like to setup a git workflow that would let me auditing the commits made by this developer (and possibly reject them) without forcing him to rebase his work (which is error prone for new users). 我正在与一个刚接触git的开发人员合作,我想设置一个git工作流,让我审核这个开发人员的提交(并可能拒绝他们)而不强迫他改变他的工作(这很容易出错)对于新用户)。

Here is the scenario : 这是场景:

  • the master branch contains only audited code master分支仅包含经过审计的代码
  • devel branch is created by forking master branch devel分支是由分支master分支创建的
  • a developer is working on the devel branch and push his code for me to audit 开发人员正在devel分支并推送他的代码供我审核
  • I detect some issues with his code, so I ask him to make more commits on devel branch to fix the issue 我发现他的代码存在一些问题,所以我请他在devel分支上做更多的提交以解决问题
  • Once I'm happy with the code, I cherry-pick (or merge with squash) the developers commits on the master branch, add my own comments and mark the commit as authored by the developer 一旦我对代码感到满意,我就会挑选(或合并壁球)开发人员在master分支上提交,添加我自己的注释并标记由开发人员编写的提交
  • The developer merge back the master branch into his devel branch 开发人员将master分支合并回他的devel分支

Here is a visual illustration of this scenario : 以下是此方案的直观说明:

视觉情景

After this sequence, how can I be 100% sure that mistakes made by the developer during the "make mistakes / redo" sequence will not show up again when the developer will push his devel branch again after some other commits ? 在这个序列之后,如果开发人员在其他一些提交之后再次推送他的devel分支,我怎么能100%确定开发人员在“犯错误/重做”序列期间所犯的错误不会再出现?

The best solution would be to ask the developer to rebase his devel branch against the master one, but this is a hard task to new git users. 最好的解决方案是要求开发人员将他的devel分支与master重新绑定,但对于新的git用户来说这是一项艰巨的任务。

If this workflow is wrong in any way, please suggest me another where I would be able to audit the commits before merging them into the master branch. 如果这个工作流程有任何错误,请建议我另一个我可以在将它们合并到主分支之前审核提交的地方。

EDIT 编辑

A friend suggested me a direction that looks promising : the --fixup option when doing commit. 一位朋友向我建议了一个看起来很有希望的方向:提交时的--fixup选项

--fixup=<commit>

Construct a commit message for use with rebase --autosquash . 构造一个用于rebase --autosquash的提交消息。 The commit message will be the subject line from the specified commit with a prefix of "fixup! ". 提交消息将是指定提交的主题行,前缀为“fixup!”。 See git-rebase for details. 有关详细信息,请参阅git-rebase

This option could be used by the developer to properly mark his second and third commits as a fix for his first one. 开发人员可以使用此选项将第二次和第三次提交正确标记为第一次提交。 A good solution to explore... 探索的好方法......

Remark 1: By trying to turn the separated commits on devel into a single commit on master , you are rewriting history. 备注1:通过尝试将devel上的分离提交转换为master上的单个提交,您重写历史记录。 I see the point in trying to keep a clean, linear history on master , however a less linear history with merges would be more easily integrated with git basic commands. 我看到了尝试在master上保持干净,线性历史的观点,但是使用合并的较不线性的历史将更容易与git基本命令集成。

Remark 2: If your workflow explicitly includes members which are not familiar with the basic tools you use to share code, you should live with the consequences. 备注2:如果您的工作流程明确包含不熟悉您用于共享代码的基本工具的成员,那么您应该承担后果。 At some point, I think the developer should learn git. 在某些时候,我认为开发人员应该学习git。

Here are two suggestions : 这有两个建议:

  1. Drop the linear history on master, and "validate" the changes by running, from master : 删除master上的线性历史记录,并通过从master运行来“验证”更改:

     git merge --no-ff devel 

    This is the most straightforward way to inform git that the modifications on devel are taken into account on master . 这是告知git在master上考虑devel上的修改的最直接的方法。

  2. Do the merge with devel yourself, and have your developer pull the modifications from origin/devel . 自己devel合并,并让开发人员从origin/devel提取修改。
    If the single commit on master really only consists in squashing the commits on devel , this shouldn't trigger any conflicts -- the merge commit master -> devel should introduce 0 modifications. 如果master上的单个提交实际上只包括压缩devel上的提交,这不应该触发任何冲突 - merge commit master - > devel应该引入0修改。
    If you have actually modified the squashed commit, and the developer can have local modifications of his own, you have to face the possibility of triggering conflicts on his side anyway ... 如果你实际上修改了压扁的提交, 并且开发人员可以对他自己进行本地修改,那么无论如何你都必须面对触发冲突的可能性......

If you're going to just squash the dev branch instead of merging it normally, it's not a good idea to then merge that squashed commit back into the dev branch, because then you'll get a ton of confusing conflicts, because git thinks you're applying new code, when in fact it's actually the same code. 如果你只是压缩dev分支而不是正常合并它,那么将那个压扁的提交合并回dev分支并不是一个好主意,因为那样你会得到大量令人困惑的冲突,因为git认为你正在应用新代码,实际上它实际上是相同的代码。

It would be better to either just do a simple merge into master , then a simple merge back into devel , or otherwise throw-away the devel branch and make a new one off of the most recent commit of master . 最好是简单地合并到master ,然后简单地合并回devel ,或者抛弃devel分支并从最近的master提交中创建一个新的。 As long as the code that you merge into master is "good", according to you, then you probably won't get any regressions. 根据你的说法,只要你合并到master的代码是“好的”,那么你可能不会得到任何回归。

On the other hand, if you go with your original plan of merging in squashed commits back into devel , that will increase your chances of a regression occurring, because of the confusing conflicts. 另一方面,如果你按照原来的计划将压缩的提交合并回到devel ,那么由于冲突的混乱,这将增加你发生回归的机会。

Update 更新

I deleted parts of my answer above because I actually just tested doing the squash commit on master and then immediately merging it back into devel , and it didn't cause any conflicts, so that part of my answer was incorrect. 我删除了上面部分答案,因为我实际上刚刚测试了对master进行了squash commit,然后立即将它合并回devel ,并且它没有引起任何冲突,因此我的部分答案是不正确的。

I turned this into answer into a community wiki because it still contains a lot of information about the problem in the comments. 我把它变成了社区维基的答案,因为它在评论中仍然包含很多关于问题的信息。

Just use gerrit. 只需使用gerrit。 With gerrit you will have the history of your comments, commits etc. You can also abandon change. 使用gerrit,您将拥有您的评论,提交等历史记录。您也可以放弃更改。 The workflow I use as a developer: 我作为开发人员使用的工作流程:

Prepare 准备

Copy gerrit commit-message hook to your repo/.git/hooks . 将gerrit commit-message hook复制到repo/.git/hooks Make sure it's executable and doesn't contains crlf. 确保它是可执行的,不包含crlf。

Make remote review for pushing, or better shell alias if you work on *nix. 如果您使用* nix,请对推送或更好的shell别名进行远程审核

Make alias for rebasing in ~/.gitconfig (about fork-point ) 在〜/ .gitconfig(关于fork-point )中为rebase创建别名

[alias]
        reb = !"git rebase -i $(git merge-base --fork-point origin/master HEAD)"

Workflow 工作流程

while unapproved do
    git commit -a --amend
    git push review
    # reviewers comment, reject, approve etc.
    # If rejected, I change commit as required, then
end

Squashing 挤压

When pushing to gerrit there should (probably) be only one commit. 当推向gerrit时,应该(可能)只有一次提交。

So to squash commits on your branch into one: 所以要将你的分支上的提交压缩成一个:

git reb

Editor will open. 编辑将开放。 Change pick to squash for every line except first (oldest commit). 除了第一个(最早的提交)之外,将每个行的pick更改为squash Save and quit. 保存并退出。 Editor will open with commit messages. 编辑器将打开提交消息。 Delete everything except oldest commit message and the line with Commit-ID (it's needed for gerrit). 删除除最旧的提交消息之外的所有内容以及具有Commit-ID的行(gerrit需要它)。

Rebasing 垫底

If merging your branch fails in gerrit, you can rebase it onto origin/master 如果合并你的分支在gerrit中失败,你可以将它重新定位到origin / master

git rebase origin/master

If there are many conflicts, you can avoid pain of resolving many of them just by using cherry-pick 如果有很多冲突,你可以通过使用樱桃选择避免解决其中许多冲突的痛苦

git checkout -b topic2 origin/master
git cherry-pick topic
git branch -D topic
git branch -m topic

git review git评论

You can also use git review to simplify some operations when working with gerrit. 在使用gerrit时,您还可以使用git review来简化某些操作。

If you make sure your other developer always creates changes from a certain branch, say develop, you can have main branch setup that always exist for example: 如果您确保您的其他开发人员始终从某个分支创建更改,例如develop,您可以拥有始终存在的主分支设置,例如:

master, develop 掌握,发展

If your developer only creates feature branches from the develop branch he can create commits all he wants. 如果您的开发人员只从开发分支创建功能分支,他可以创建他想要的所有提交。 Then when you think it is ready you can cherry-pick/rebase and do your thing with it. 然后,当你认为它准备就绪时,你可以挑选/改变并用它来做你的事情。 The feature branch gets deleted making sure rewritten history is gone. 功能分支被删除,确保重写的历史记录消失。

All your developer needs to remember would be to create a branch from the remote develop branch everytime he wants to start a new feature and not touch his local feature branch when you say you're going to merge some stuff into your develop. 您需要记住的所有开发人员都需要在每次想要启动新功能时从远程开发分支创建分支,而在您说要将某些内容合并到开发中时不要触摸他的本地功能分支。

Then when it is ready he deletes his myfeature branch locally and you delete it remote when you've merged/rebased/cherry-picked his good changes into your develop. 然后当它准备就绪时,他会在本地删除他的myfeature分支,当你合并/重新定位/樱桃选择他的好的变化进入你的开发时,你会远程删除它。

Only the good commits go into develop branch. 只有好的提交进入开发分支。 Your developer creates new branch from develop like before. 您的开发人员像以前一样从开发创建新分支。

I think some basic branching is the least your developer should know. 我认为一些基本的分支是你的开发人员应该知道的最少。 If he cannot rebase/clean his branch/commits I think you have to agree to follow a certain workflow. 如果他不能改变/清理他的分支/提交,我认为你必须同意遵循某个工作流程。

Maybe not perfect, but perhaps a possible workflow nonetheless. 也许并不完美,但也许是一种可能的工作流程。 Hope it helps. 希望能帮助到你。

The easiest way with the least amount of fuss would just be to merge in the changes from the devel branch into master. 最简单的方法是将devel分支中的更改合并到master中。 You just need to regularly update the branch with master so that your branches don't diverge too wildly (depending on what features other people are working on). 您只需要定期使用master更新分支,这样您的分支就不会过于分散(取决于其他人正在处理的功能)。

If you want to have one single commit for the modification on master. 如果您希望在master上进行一次修改。 You can rebase the developers commits into one single commit and then cherry-pick that commit onto master. 您可以将开发人员提交的内容重新绑定到一个提交中,然后将其提交给master。 This would lead to complications as you would only be able to do git push -f to update the remote devel branch and if your developer is not familiar with git would be complicated for updating their devel branch. 这会导致复杂化,因为您只能执行git push -f来更新远程devel分支,如果您的开发人员不熟悉git,则更新其devel分支会很复杂。 Or you would require that they delete that branch and then use a new branch for any future work. 或者您要求他们删除该分支,然后使用新分支进行任何后续工作。

You will need to decide which option to go on based on whether or not you want to have all the commits from your developer showing up in the log. 您需要根据是否要让开发人员的所有提交显示在日志中来决定继续选择哪个选项。 The easiest and least troublesome way is just to simply merge devel and master. 最简单,最麻烦的方法就是简单地合并devel和master。

I will test the following workflow and let you know if things are going well. 我将测试以下工作流程,并告知您事情进展顺利。

Prerequisites 先决条件

  • developer must be able to commit from the command line 开发人员必须能够从命令行提交
  • developer should always stay on the same branch, so that he does not need to worry about which branch is currently checked out 开发人员应始终保持在同一分支上,这样他就不必担心当前检出的分支
  • developer should never have to solve conflicts that impact code he does not have written 开发人员永远不应该解决影响他没有编写的代码的冲突
  • developer will never be in a situation where he could lost local modifications to its working tree 开发人员永远不会处于他可能失去对其工作树的本地修改的情况

Tools 工具

git commit with the --fixup option : git commit使用--fixup选项 git commit

--fixup=<commit>

Construct a commit message for use with rebase --autosquash . 构造一个用于rebase --autosquash的提交消息。 The commit message will be the subject line from the specified commit with a prefix of "fixup! ". 提交消息将是指定提交的主题行,前缀为“fixup!”。

git rebase with --autosquash, --autostash and --interactive options git rebase with --autosquash, - autostash和--interactive options

--interactive

Make a list of the commits which are about to be rebased. 列出即将重新定位的提交。 Let the user edit that list before rebasing. 让用户在变基之前编辑该列表。 This mode can also be used to split commits. 此模式也可用于拆分提交。

--autosquash

When the commit log message begins with "squash! ..." (or "fixup! ..."), and there is a commit whose title begins with the same ..., automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified, and change the action of the moved commit from pick to squash (or fixup ). 当提交日志消息以“squash!...”(或“fixup!...”)开头,并且有一个提交标题以相同的...开头时,自动修改rebase -i的待办事项列表标记为压缩的提交在修改提交之后立即生效,并将已移动提交的操作从pick更改为squash (或fixup )。 Ignores subsequent "fixup! " or "squash! " after the first, in case you referred to an earlier fixup/squash with git commit --fixup/--squash . 在第一个之后忽略后续的“fixup!”或“squash!”,如果您使用git commit --fixup/--squash引用了早期的fixup / git commit --fixup/--squash

This option is only valid when the --interactive option is used. 此选项仅在使用--interactive选项时有效。

If the --autosquash option is enabled by default using the configuration variable rebase.autosquash , this option can be used to override and disable this setting. 如果默认情况下使用配置变量rebase.autosquash启用--autosquash选项,则此选项可用于覆盖和禁用此设置。

--autostash

Automatically create a temporary stash before the operation begins, and apply it after the operation ends. 在操作开始之前自动创建临时存储,并在操作结束后应用它。 This means that you can run rebase on a dirty worktree. 这意味着您可以在脏工作树上运行rebase。 However, use with care: the final stash application after a successful rebase might result in non-trivial conflicts. 但是,谨慎使用:成功重组后的最终存储应用程序可能会导致非平凡的冲突。

Workflow 工作流程

  1. The developer fork the master branch into a devel branch. 开发人员将master分支分成一个devel分支。 The fork point is marked with a tag (for exemple version_1.1 ) fork point标有标记(例如version_1.1
  2. The developer work and commit on the devel branch. 开发人员在devel分支上工作和提交。 When the work is done, he pushes his branch on the remote repository so that the auditor can see and validate it. 完成工作后,他将其分支推送到远程存储库,以便审核员可以查看和验证它。
  3. The auditor fetch the devel branch and look at the code. 审计员获取devel分支并查看代码。 If something is not correct, he asks the developer to make some modifications. 如果某些事情不正确,他会要求开发人员进行一些修改。
  4. For each modification done by the developer, the following command should be used to commit the correction : git commit --fixup <commit that was not OK> . 对于开发人员完成的每个修改,应使用以下命令提交更正: git commit --fixup <commit that was not OK> Than the branch is pushed again. 比分支再次被推。
  5. Once the auditor is happy with the modifications done, the developer must rebase his branch in order to squash all the fixup commits into one beautiful and error-free commit (other unrelated work could have been commited meanwhile). 一旦审核员对完成的修改感到满意,开发人员必须重新分支他的分支,以便将所有修复提交压缩成一个漂亮且无错误的提交(其他无关的工作可能同时被提交)。

GIT_EDITOR=: git rebase tags/version_1.1 --interactive --autosquash --autostash . GIT_EDITOR=: git rebase tags/version_1.1 --interactive --autosquash --autostash

The GIT_EDITOR=: is here to avoid to display the editor that present the commit lists due to the --interactive option. GIT_EDITOR=:这里是为了避免显示由于--interactive选项而出现提交列表的编辑器。 This option is needed to make the fixup commit reorder automatically. 需要此选项才能使fixup提交自动重新排序。

The last step is to push the devel branch again (with --force option) so that the auditor can merge it in the master branch. 最后一步是再次推送devel分支(使用--force选项),以便审计员可以将其合并到master分支中。 The rebase base for next devel fixup could be the master branch or a new tag that the developer put on his devel branch after merging back the master branch. 下一个devel fixup的rebase base可以是主分支或开发人员在合并回master分支后放在他的devel分支上的新标记。

Here is the resulting git tree : 这是生成的git树:

修复工作流程的gitk插图

Well, if you have one beginner developer and you are the only reviewer, i suggest this workflow: 好吧,如果你有一个初学者开发者并且你是唯一的评论者,我建议这个工作流程:

  1. the developer create a local branch from master to implement some feature (branch name: i-123) 开发人员从master创建本地分支以实现某些功能(分支名称:i-123)
  2. the developer add some code to branch i-123 开发人员将一些代码添加到分支机构i-123
  3. the developer create merge request to merge i-123 on master branch 开发人员创建合并请求以在主分支上合并i-123
  4. the reviewer find some mistake and notifies the problem to developer 审稿人发现了一些错误并将问题通知给开发人员
  5. the developer add commits to solve problem and notifies to reviewer to check change of i-123 branch 开发人员添加提交以解决问题并通知审阅者检查i-123分支的更改
  6. the reviewer verifies the source code and accept merge request (merge i-123 on master branch as result i-123 was destroyed) 审阅者验证源代码并接受合并请求(在主分支上合并i-123,因为结果i-123被销毁)
  7. the developer sync local repository (as result: master branch contain change relative to i-123 and i-123 was destroyed) 开发人员同步本地存储库(结果:主分支包含相对于i-123的更改并且i-123被销毁)
  8. the developer can continue with step 1 开发人员可以继续第1步

This approach allow that one developer work on one or various features at same time, and eliminate complicate logic about mantein updated develop branch. 这种方法允许一个开发人员同时处理一个或多个功能,并消除关于mantein更新开发分支的复杂逻辑。 It's easy approach to the beginner developer. 这对初学者开发者来说很简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在不进行所有提交的情况下重写git repo历史记录 - Rewriting git repo history without going through all commits 在Git中恢复一系列推送的合并和提交(无需重写历史记录) - Reverting a series of pushed merges and commits in Git (without rewriting history) 重写git历史记录,重写添加和删除提交 - Rewriting git history, rewrite addition and removal commits git工作流程:维护功能提交的历史记录 - git workflow: maintaining a history of functional commits git工作流程:在历史记录中保持不一致的提交 - git workflow: keeping inconsistent commits in history 合并和压缩提交而不保存历史记录的Git工作流 - Git workflow to merge and squash commits and not keep history 提交作者应该如何处理作者关于历史重写的日期(Git)? - What the author of commits is supposed to do with the author date on history rewriting (Git)? Git:重写历史记录以使用相同的消息和时间折叠提交(合并子模块) - Git: rewriting history to collapse commits with the same message and time (merging submodules) 是否可以在不重写历史记录的情况下缩小.git存储库? - Is it possible to slim a .git repository without rewriting history? Git:允许在不删除历史记录的情况下修改提交 - Git: Allow amending commits without erasing the history
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM