Skip to content

Redesign questions #142

@grimmySwe

Description

@grimmySwe

@ingydotnet When I started to write some documentation and tried to explain how git-subrepo works I came to some insights. (I have discussed this a lot with @jrosdahl )

The main reason for these thoughts are that the most common use case where you repeatedly pull things and have some minor local change would be increasingly more difficult. Every time you pull you would find the common ancestor further back in history and you would have to solve the same conflicts over and over again. We already discussed in other issues that it would be nice if you could avoid having an extra branch if you want local changes.

  • When performing a pull, it should be possible to use the pull reference in .gitrepo instead of the merge-base command. And instead of rebasing onto the new branch you should be able to simply apply the diff between the current state and the rebase parent. As the commits get squashed anyway.
    • Replace subrepo merge-base with simple use of .gitrepo.commit
    • Replace rebase with merge
    • Simplify subrepo branch
D(a) - E(a) - F(a) project   (commit(.gitrepo.commit))
a - b - c subrepo
$ git subrepo pull
* fetch
a - b - c subrepo/fetch
* branch
d - e - f subrepo/branch
* reparent f on a (see further down for reparenting tool)
a - b - c subrepo/fetch
  \
    f subrepo/branch
* merge, solve conflicts
a - b - c - g subrepo/fetch
 \         /
     f            subrepo/branch
* return to project
* write contents from g into subrepodir
* Update .gitrepo file
* commit
D(a) - E(a) - F(a) - G(g) project

Note that you if you really want to use rebase instead of merge you can do the reparenting on e instead and rebase the entire branch step by step. It will though add a little complexity as you would need to find out the first commit with the last .gitrepo.commit. I guess that one way would be to iterate from the HEAD and find the first one.

  • For the push case it's a little bit trickier, in our use case it might be better to squash the push commit as well. Then you have the freedom of simply using the same simple logic of comparing the changes from the latest pull point and apply them to subrepo. If you keep the condition that you need to pull before you push it might even be simpler as all you need to do is create a new commit with the content of project/subrepo
    • Squash subrepo upstream
    • Simplify subrepo branch
D(a) - E(a) - F(a) project   (commit(.gitrepo.commit))
a subrepo
* fetch
a subrepo/fetch
* branch
d - e - f subrepo/branch
* checkout subrepo/fetch
* write contents of f 
* commit (it will though get a new commit hash)
a - f subrepo/fetch
* push
a - f subrepo
  • If you really want to push all commits into the subrepo there are some strange things occuring. The commit sequence that appears in the subrepo is not linear, as the changes will occur in a rebased order including possible "pull" commits that reintroduces the changes already existing in the subrepo.

I found a tool for reparenting:
https://github.com/MarkLodato/git-reparent

When I think about it I guess that you could make the branch command work on only the last commit. That way you have constant speed. Current design will increase the time for each commit.

$ git checkout -b subrepo/branch
$ git filter-branch --subdirectory-filter subrepo -- HEAD^..HEAD

I haven't done any coding yet, all of this came up when I tried to describe how git-subrepo works.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions