git subrepo push creates new timestamps each time, which results in new commits/hashes on the remote. This makes it hard to manage and then push branches, tags, and dependencies between commits on the remote.
Related to #668 and provides additional/different context.
when you do a push we replay your changes on top of the remotes repo in a workspace. You are getting the date for the replay instead of the original commit.
My specific use case is using pull request stacks (https://www.stacking.dev/ and https://github.github.com/gh-stack/).
What I like to do (without subrepo):
I organize a large change into several commits, tagging commits with branches for pull requests. Branches/pull requests are divided to be reviewed individually, but may form a chain or DAG of dependencies. This makes it easier to review by making the reviews smaller and focused on single atomic concepts and then allows merging gradually. While it can complicate the review and merge process if an earlier/dependent review requires a change, it's also helpful for reviewers to see the full context and how changes build on one another.
Imagine a chain of pull requests/branches:
PR1 ("branch 1") <- PR2 ("branch 2") <- PR3 ("branch 3")
Each branch is pushed and pull requests are opened targeting the previous branch in the chain (e.g., PR2 is for branch 2 to merge into branch 1). When eventually merging the next PR must be git rebase --onto main <just-merged-PR> unless using github's not-yet-GA stack feature.
If the review for PR1 requires a change this would be addressed by:
- check out PR1 locally
- make a change to address the review. Commit.
- check out the last branch in the stack (PR3/branch 3). Rebasing to PR1/branch 1 with
--update-refs so that intermediate branches (branch 2) are also updated. This maintains the linear structure (see https://andrewlock.net/working-with-stacked-branches-in-git-is-easier-with-update-refs/ for a good explanation of this pattern).
git push --force-with-lease each branch.
How this breaks with subrepo:
Assume I have a large change in a repo with several subrepos. I structure it into several commits where each commit changes files in only one subrepo. I create branches at the commits that I would like to be pull requests. I git subrepo push each of those branches to the remote.
Because they are distinct git subrepo push and each push uses the push time as the replayed commit time the branches will each have distinct commits and will not share history. I cannot open a pull request from the pushed PR2 into PR1 because branch 1 on the remote is not in the history of branch 2. They have similar commits with different commit timestamps and different hashes. To address this I have to push only the last branch (PR3) and then create the branches in the remote. If the branches for dependent PRs do not form a linear chain (e.g., if there's a PR4 that depends on PR2 but not PR3) I don't have a good solution.
If I later need to make an update to PR1 and doing so is easier from the "super repo" containing the subrepos (because I have cross-repo tests set up or I'm using this super repo to provide cross-repo context to an agent) I can't just subrepo push each branch because it rewrites history on the remote, even for commits that I haven't changed. I have to against push the last branch and then recreate/reset all of the branches on the remote side.
I understand why it currently works the way it does. I'm providing context to add to #668 as to why it's helpful to maintain commit timestamps and hashes even through a push.
I'd also like to push back on the comment (not to argue, but to justify why it's correct to propagate the commit creation time)
Which date are you referring to in this request? I added tests and note that the Author Date remains the same, but the Commit Date updates. This seems reasonable since the patch wasn't on the external repo until the push
From the perspective of distributed revision control such as git it doesn't matter that the patch wasn't on the external repo. There's no "source of truth" repo (unless you choose that paradigm). The commit was created when it was created locally and when it is pushed or fetched it is still that same commit. I want the option for git subrepo to provide that same model.
For comparison git subtree --split does create deterministic hashes. If you have a local commit C1 and a git subtree --split gives it hash C1' on the remote, and then add a subsequent commit C2 (so you have C1 <- C2) then when you git subtree --split you have on the remote C1' <- C2'.
...but git subtree --split is crazy slow, which is what led me to try git subrepo in the first place!
git subrepo pushcreates new timestamps each time, which results in new commits/hashes on the remote. This makes it hard to manage and then push branches, tags, and dependencies between commits on the remote.Related to #668 and provides additional/different context.
My specific use case is using pull request stacks (https://www.stacking.dev/ and https://github.github.com/gh-stack/).
What I like to do (without subrepo):
I organize a large change into several commits, tagging commits with branches for pull requests. Branches/pull requests are divided to be reviewed individually, but may form a chain or DAG of dependencies. This makes it easier to review by making the reviews smaller and focused on single atomic concepts and then allows merging gradually. While it can complicate the review and merge process if an earlier/dependent review requires a change, it's also helpful for reviewers to see the full context and how changes build on one another.
Imagine a chain of pull requests/branches:
PR1 ("branch 1") <- PR2 ("branch 2") <- PR3 ("branch 3")
Each branch is pushed and pull requests are opened targeting the previous branch in the chain (e.g., PR2 is for branch 2 to merge into branch 1). When eventually merging the next PR must be
git rebase --onto main <just-merged-PR>unless using github's not-yet-GA stack feature.If the review for PR1 requires a change this would be addressed by:
--update-refsso that intermediate branches (branch 2) are also updated. This maintains the linear structure (see https://andrewlock.net/working-with-stacked-branches-in-git-is-easier-with-update-refs/ for a good explanation of this pattern).git push --force-with-leaseeach branch.How this breaks with subrepo:
Assume I have a large change in a repo with several subrepos. I structure it into several commits where each commit changes files in only one subrepo. I create branches at the commits that I would like to be pull requests. I
git subrepo pusheach of those branches to the remote.Because they are distinct
git subrepo pushand each push uses the push time as the replayed commit time the branches will each have distinct commits and will not share history. I cannot open a pull request from the pushed PR2 into PR1 because branch 1 on the remote is not in the history of branch 2. They have similar commits with different commit timestamps and different hashes. To address this I have to push only the last branch (PR3) and then create the branches in the remote. If the branches for dependent PRs do not form a linear chain (e.g., if there's a PR4 that depends on PR2 but not PR3) I don't have a good solution.If I later need to make an update to PR1 and doing so is easier from the "super repo" containing the subrepos (because I have cross-repo tests set up or I'm using this super repo to provide cross-repo context to an agent) I can't just
subrepo pusheach branch because it rewrites history on the remote, even for commits that I haven't changed. I have to against push the last branch and then recreate/reset all of the branches on the remote side.I understand why it currently works the way it does. I'm providing context to add to #668 as to why it's helpful to maintain commit timestamps and hashes even through a push.
I'd also like to push back on the comment (not to argue, but to justify why it's correct to propagate the commit creation time)
From the perspective of distributed revision control such as git it doesn't matter that the patch wasn't on the external repo. There's no "source of truth" repo (unless you choose that paradigm). The commit was created when it was created locally and when it is pushed or fetched it is still that same commit. I want the option for
git subrepoto provide that same model.For comparison
git subtree --splitdoes create deterministic hashes. If you have a local commit C1 and agit subtree --splitgives it hash C1' on the remote, and then add a subsequent commit C2 (so you have C1 <- C2) then when yougit subtree --splityou have on the remote C1' <- C2'....but
git subtree --splitis crazy slow, which is what led me to trygit subrepoin the first place!