git workflow for a project with open-source and proprietary (private) part [closed]

◇◆丶佛笑我妖孽 提交于 2021-02-08 10:18:34

问题


Wordpress plugin with free and PRO version. The PRO version contains additional files, scattered across the codebase.

What is the optimal strategy to track both versions in git, satisfying the following constraints:

  1. free version is open-source on GitHub, accepting contributions;
  2. PRO version synced with a private repository;
  3. local development takes place on the PRO version (e.g. for refactoring to work);
  4. both histories are related (history of PRO ⊇ free)
  5. low-maintenance:
    1. we are git noobs,
    2. no manual accounting of what file fits where.

There are numerous Wordpress plugins following this exact free vs. PRO dichotomy. How are they versioned?


回答1:


A few simple approaches come to mind ...

Separate Namespace

Move all scattered files into a separate namespace directory, such as ./pro, into which you clone the separate PRO repository, containing only the PRO files. Drawback: The checkouts of the two repositories would have to be kept in sync (i.e. if you switch to an old commit in one repo, you'd always also need to switch to a compatible commit in the other repo).

Two Repositories

This, I suppose, is how it's normally done. Maintain free and PRO versions in two distinct repositories. Let the PRO repo define the public remote source to fetch and merge the changes from.

cd ~/project-libre
git remote add origin GITHUB_PUBLIC_REPO

cd ~/project-pro
git remote add origin PRIVATE_REPO
git remote add libre GITHUB_PUBLIC_REPO  # to fetch and merge changes from

Whenever there are changes submitted to the public repository, you can merge them into your PRO version with:

cd ~/project-pro
git checkout master
git pull libre master --allow-unrelated-histories
git push origin master

Whenever there are changes in the PRO version you want to sync into the published free version, you can use git-format-patch to export the changes as patch files, then on the other end import that patchset, excluding any files that are not to published in the free version. Like so:

cd ~/project-pro
git checkout master
git format-patch HEAD~3..HEAD  # Export e.g. last three commits as patches

Now switch to free version and apply the patches (with git-am), excluding from each commit all the PRO files (paths) that are on the ignore list for the free version. I put them in a .gitignore file here in the free project root, and the command line assumes POSIX shell is available (repeats --exclude parameter for every file/path in .gitignore).

cd ~/project-libre
git checkout master
git am $(printf -- '--exclude=%s ' $(cat .gitignore)) ~/project-pro/*.patch    

Two Branches

Have two branches, each synced with a different remote.

git remote add origin  GITHUB_PUBLIC_REPO
git remote add private PRIVATE_REPO

Create two files, one free and one PRO:

touch free1 pro1

On master branch, create a .gitignore containing all the PRO files

git checkout master
echo 'pro*' > .gitignore

git add .gitignore
git commit -m 'Add .gitignore ignoring PRO files'

Sync the public branch with the public repository:

git push -u origin master

Now branch master into a private PRO branch and clear the .gitignore as the PRO files are not ignored there.

git checkout --branch master-private
echo > .gitignore

git commit .gitignore -m 'Clear .gitignore -- track all files here'

Sync the private branch with the private repository:

git push -u private master-private

Now commit free1 and pro1 files to their respective branches:

git checkout master
git add free1
git commit -m 'Add free1'

git checkout master-private
git add pro1
git commit -m 'Add pro1'

And merge master into master-private so that it contains the full set.

git checkout master-private
git merge master

You need to resolve the one .gitignore conflict (or you can specify -X ours merge switch).


Later, you do some development on master-private branch (§ 3) retouching and creating various files that would fit in either of two branches:

git checkout master-private
touch free2 pro2
echo xxx > free1
echo xxx > pro1

You don't want to enumerate all the non-PRO files to commit (§ 5.2); that's what you have the .gitignore for. You use it by switching to master and there committing everything that fits, then switching back to master-private, committing what remains. You need to stash the changes first as they would be overwritten by switching branches.

git stash
git checkout master
git stash apply

You get a conflict here about pro1 changed in stash but deleted on master. You resolve it by telling git to just continue to ignore it by unstaging it.

git reset HEAD .

Now commit all the free files:

git add free2  # Manually add the new files (easy and not violating § 5.2)
git commit -a -m 'Update to free1 and free2'

Switch back to the private branch, merge in the updated master branch, and commit the remaining files, again from stash.

git checkout master-private
git merge master
git stash pop  # The stash now applies cleanly and is removed
git add pro2  # Manual but necessary adding of new files (not violating § 5.2) 
git commit -a -m 'Update pro1 and pro2'

And that's it.


When you get a pull request on GitHub and you merge it. Afterwards just sync your local master with it and then merge it into the private branch:

git checkout master
git pull
git checkout master-private
git merge master
git push

git is easy–peasy.



来源:https://stackoverflow.com/questions/51202660/git-workflow-for-a-project-with-open-source-and-proprietary-private-part

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!