将项目从 SVN 迁移到 Gitlab CE,并在工作流程和历史上苦苦挣扎 [英] Migrated project from SVN to Gitlab CE and struggling with workflow and history

查看:10
本文介绍了将项目从 SVN 迁移到 Gitlab CE,并在工作流程和历史上苦苦挣扎的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以前的 SVN 工作流程

  • svn cp $PATH/trunk $REPO/branches/feature_xxx
  • git checkout $REPO/branches/feature_xxx
  • 开发人员处理分支的工作副本,偶尔会与 master 合并,然后将分支标记为准备合并"
  • 当功能准备就绪时,所有者执行 svn merge --reintegrate $REPO/branches/feature_xxx,运行完整的测试套件,如果一切正常,则 ``svn commit -m "merged feature_xxx"
  • 当一个版本准备好时 svn cp $REPO/trunk $REPO/tags/vX.Y.Z 并发布该标签.

svn trunk 历史看起来很干净:

版本 4.5.4特征_xxxbugfix_yyy版本 4.5.3特征_zzz版本 4.5.3错误修复_aaa

我们不关心内部提交,但如果我们愿意,我们可以使用 svn log -g 将合并的提交扩展为内部提交(有用一两次).

现在我们切换到 Git 和 Gitlab,主要是因为它具有评论合并请求和差异的功能.但我们正在努力获得同样干净的工作流程,这或多或少是这样的:

策略 1:尝试合并功能分支(通过 git 或 Gitlab合并"按钮)

好的..这很简单!Ehh wait WTF 是那些污染我主人日志的先前提交.

解决办法:没办法,这是一团糟.

策略2:了解git merge --squash

好的..这就是我们想要的..现在我们有一个很好的历史,但我们必须从命令行来做,因为 Gitlab CE 不允许它从 GUI (

<块引用>

好的..这很简单!Ehh wait WTF 是那些污染我主人日志的先前提交.

这不是一个真正的问题,但仅供参考,git loggitk 的功能允许隐藏内部提交".在这样一个历史记录中的功能分支(假设功能分支已与 --no-ff 模式合并):

工作流程

Git 中的分支和合并功能非常强大,因此有很多可能的方式来开发和集成 master 中的更改.但是,最好在自己的开发团队中遵循系统化的工作流程,两种不同的工作流程非常流行并且已被证明非常有效:

我只是提供了介绍这两个工作流程的主要参考资料的链接,但您可以在网上找到许多其他参考资料,包括 脚本,以方便 Git 流程的应用 例如.

总结一下两者的区别:Git流程有两个主要分支developmaster,有特定的发布约定,而GitHub流程更简单(没有develop 分支),更适应持续交付的情况.

变基

您在帖子中提到了一些 git rebase 命令,所以我想您熟悉此命令及其相关含义,但为了自成一体,这里有几点说明:

变基(git rebase another-branch)基本上意味着在另一个分支上重放当前分支的提交",因此变基是历史重写"的一种形式,重写提交意味着它的 SHA1 已更改.所以这里的主要规则是你不应该使用 git push 重新发布已经发布的更改.

请注意,Git 流程和 GitHub 流程都使用 git merge,而不是 git rebase.

实际上,在推送之前重写自己的本地历史记录是一种很好的做法,以确保提交是原子的或具有合理的提交消息等.为此,可以使用 git提交 --amendgit rebase --interactive parents-commit.

<块引用>

所以现在我们正在使用最后一种策略.. 大部分时间都在尝试 git rebase,但当事情变得多毛时恢复到 git merge --squash.但老实说,我们并不是 100% 满意,SVN 工作流程干净且简单.

您提到的策略 2 和 3 确实可以从仅命令行的角度来保持线性历史记录,但是这样做您实际上是在使用 Git 遵循 SVN 工作流程,而更常见的是Git 中的非线性历史并利用其功能分支设施...

<块引用>

好的..这就是我们想要的..现在我们有一个很好的历史记录,但是我们必须从命令行执行,因为 Gitlab CE 不允许从 GUI 执行它

实际上,我猜 GitLab CE 不允许您轻松做到这一点,因为它首先被设计为支持 Git 工作流(这通常意味着进行真正的合并等).

额外参考

为了更深入地了解 Git-flow/GitHub-flow 之外的可能工作流,这里有一篇很长的文章,但值得一读,由 GitLab 撰写,主题如下:https://docs.gitlab.com/ee/topics/gitlab_flow.html

另一个有用的参考是 https://git.github.io/git-reference/,它给出了主要 Git 命令的摘要,包括 git tag 我在帖子中没有提到,但使用 Git 流程非常重要.

Previous SVN workflow

  • svn cp $PATH/trunk $REPO/branches/feature_xxx
  • git checkout $REPO/branches/feature_xxx
  • developers worked on working copy of branch, ocasionally merging back with master and before marking the branch as "ready to merge"
  • when the feature was ready, owner did svn merge --reintegrate $REPO/branches/feature_xxx, run complete test suite and if everything ok then ```svn commit -m "merged feature_xxx"
  • when a release was ready svn cp $REPO/trunk $REPO/tags/vX.Y.Z and released that tag.

The svn trunk history looked nice and clean:

version 4.5.4
feature_xxx
bugfix_yyy
version 4.5.3
feature_zzz
version 4.5.3
bugfix_aaa

We don't care about internal commits, but if we wanted we can use svn log -g that will expand the merged commits into it's internal ones (was useful one or two times).

Now we switched to Git and Gitlab, mosty because of it's feature to comment on merge requests and diffs. But we are struggling to get the same clean workflow, this was more or less what happened:

Strategy 1: attemped to merge a feature branch (via git or Gitlab "Merge" button)

Ok.. this is easy! Ehh wait WTF are those previous commits that are polluting my master's log.

Resolution: no way, this is a mess.

Strategy 2: learned about git merge --squash

Ok.. this is what we want.. now we have a nice history, but we have to do it from command line because Gitlab CE doesnt' allows it from GUI (https://gitlab.com/gitlab-org/gitlab-ce/issues/34591). No big deal, we do it from command line.. oh wait, why hasn't Gitlab detected we closed the merge request..!? that was happening automatically before.

So, we learned there is no way for it to detect the branch was merged.. sure there is another way (eg. closing with a commit message). Ups not implemented yet: https://gitlab.com/gitlab-org/gitlab-ce/issues/13268.

Resolution: the history looks nice, BUT we need to manually close the merge requests so we loose the ability to track which ones we closed as "not intented to do" from "closed but merged manually via squash". Sure there must be a better way..

Strategy 3: learned about git rebase..

Ok, so when a branch is finished we do git rebase origin/master and then git rebase -i XXXXX where XXXX is the oldest common ancestor and we sqash all commits with a message "implemented feature_xxx". And then we simply merge with master via cmd line or GUI.

Resolution: now gitlab detects which merge requests are merged.. good. But rebasing can be a PITA for long branches and a loss of time sometimes, so when things get hairy we simply go back to merge --squash. Also the log is not so clean becaouse we have for every branch the implemented feature_xxx and then merged feature_xxx commits.. it's not as bad as simply merging but still is noise.

Conclusion

So now we are using the last strategy.. trying to git rebase most of the time but reverting to git merge --squash when things get hairy. But to be honest we are not 100% happy, the SVN workflow was clean and simpler.

Are we missing something? Thanks

解决方案

Migrating from Subversion to Git is not an easy task because Git is much more powerful and more complex. But it is definitely a fruitful move. Here is a set of related remarks/advice/references:

Atomic commits

We don't care about internal commits, but if we wanted we can use svn log -g that will expand the merged commits into it's internal ones (was useful one or two times).

Even if you don't want all the time to look at the internal commits that constitute a feature, with Git the best practice is to "commit early and often". The idea is to make each commit small and implement (or fix) only one thing. See for example this blog article atomic-commits. There are also best practices to write "good commit messages", see this article or that one.

I recall that in Git, each commit has a lot of metadata (an author name + e-mail + timestamp; a committer name + e-mail + timestamp; and a SHA1 signature) and contrarily to SVN, git commit only acts locally, so that you need to do git push to publish your changes to a remote repository. All this meta-data can be shown by GUI tools such as gitk.

Feature branches

Among the 3 strategies you are mentioning, the first one is definitely the best one: create one feature branch per feature, then "merge" them in master. But this strategy has several variants that I'll elaborate in the Workflows section below.

Strategy 1: attemped to merge a feature branch (via git or Gitlab "Merge" button) Resolution: no way, this is a mess.

A key concept to know about merges is the notion of fast-forward merge vs. non fast-forward merge or true merge.

If both types of merge are possible, the CLI command git checkout master && git merge feature will do a fast-forward merge, which could be acceptable if the feature branch contains only one commit. Otherwise it is best practice to force doing a non-fast-forward merge by doing git merge --no-ff feature. But if you don't use command-line and instead click on the "Merge" button of GitHub or GitLab, it will perform a non-fast-forward merge.

The advantage of a non-fast-forward merge (= true merge) is that your history looks like a tree (unlike SVN's typical linear history) that allows one to easily keep track of the subset of commits that belongs to the feature.

See for example this screenshot of gitk with a possible master history with 2 branches merged:

Ok.. this is easy! Ehh wait WTF are those previous commits that are polluting my master's log.

This is not really an issue, but FYI there is a feature of git log and gitk that allows to hide the "internal commits" of the feature branches in one such history (assuming the feature branches have been merged with --no-ff mode): the --first-parent option.

Here is a screenshot corresponding to the same example with gitk --first-parent:

Workflows

Branching and merging is very powerful in Git so that there are many possible ways to develop and integrate changes in master. However, it is better to follow a systematic workflow in one's development team, and two different workflows are very popular and have been proven to be very effective:

I just put a link to the main reference presenting these two workflows but you can find many other references on the Web, including scripts to facilitate the application of the Git flow for example.

To summarize the difference between the two: the Git flow has two main branches develop and master, with specific conventions for releases, while the GitHub flow is simpler (no develop branch) and more adapted to the case of continuous delivery.

Rebasing

You mentioned some git rebase commands in your post so I guess you are familiar with this command and related implications, but just to be self-contained here are several remarks:

Rebasing (git rebase another-branch) basically means "replaying the commits of current branch upon another branch", so rebasing is a form of "history rewriting", and rewriting a commit implies its SHA1 is changed. So the main rule here is that you should not rebase changes that have been already published with git push.

Note that both Git flow and GitHub flow use git merge, but not git rebase.

Actually, it is good practice to rewrite one's local history before pushing, to ensure that the commits are atomic or have sensible commit messages, etc. To this aim, one can use git commit --amend or git rebase --interactive ancestor-commit.

So now we are using the last strategy.. trying to git rebase most of the time but reverting to git merge --squash when things get hairy. But to be honest we are not 100% happy, the SVN workflow was clean and simpler.

The strategies 2 and 3 you mention are indeed possible from a command-line-only perspective to keep a linear history, but doing this you'd actually be following a SVN workflow with Git, while it is much more usual to have a non-linear history in Git and take advantage of its feature branches facilities...

Ok.. this is what we want.. now we have a nice history, but we have to do it from command line because Gitlab CE doesnt' allows it from GUI

Actually I guess that GitLab CE doesn't allow you to do this easily because it has been designed in the first place to support Git workflows (which typically implies doing true merges and so on).

Extra references

For more insight on possible workflows beyond the Git-flow/GitHub-flow, here is a long article, but worth reading, written by GitLab on these topics: https://docs.gitlab.com/ee/topics/gitlab_flow.html

Another useful reference is https://git.github.io/git-reference/, which gives a summary of the main Git commands, including git tag that I did not mention in my post but which is very important what it comes to using the Git flow.

这篇关于将项目从 SVN 迁移到 Gitlab CE,并在工作流程和历史上苦苦挣扎的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆