Conversation
mislav
left a comment
There was a problem hiding this comment.
I'm fired up about this command!
I would like to see two major simplifications to the command's implementation:
- Removal of the interactive prompt. I think that the prompt doesn't add much value to the user, but adds much complexity to the command. As far as I'm concerned as a user, syncing should always "just work" unless a sync would result in a loss of data. In that case, it should fail and instruct me to use
--force. - Splitting up the mode of running when we are syncing the local git repo vs. syncing a remote fork with its parent. I feel these are two very different approaches, but I think they are intertwined in code. Having two completely separate implementations could be beneficial for long-term maintenance of this command.
I'm not 100% sure I agree with this, though I see what you mean. I'm wondering whether for a lot of people if the prompt is just an extra level of confidence that it's going to do what they think it's going to do (or not). Given how confused we all were in talking through all the possible scenarios, I'm just concerned that if it "just works" it raises the potential for uncertainty and frustration. Open to either way, but wanted to raise that for discussion with the team. |
This reverts commit 096f30a.
|
@billygriffin @vilmibm @mislav At first I was of the mind that the confirmation prompt helped with reducing confusion of the command, and in our offline discussion I said as much, but after addressing the PR comments and working on the documentation for the command more I have flipped my opinion to match @mislav. The confirmation prompt doesn't add a lot of value. I think when we originally discussed the functionality that this command would encompass, it was confusing because we were envisioning it doing a lot more, but in its current form I think this command is fairly straight forward. Additionally, I think that if we are trying to reduce confusion about what a command is doing a confirmation prompt is not the right solution, but improving docs or reworking the command to do less is more appropriate. Lastly, the command is not doing anything destructive unless the |
|
that works for me. |
vilmibm
left a comment
There was a problem hiding this comment.
I did some testing and I'm a bit concerned about the reliability of this command; I quickly got into a state that was confusing and erroneous.
Setup
I have two repositories:
- evilmibm/cackle
- vilmibm/cackle (fork of evilmibm/cackle)
I cloned vilmibm/cackle, setting evilmibm/cackle as the base repo.
I then committed to both parent and fork, ensuring there would be a conflict.
expected conflict, got false positive
gh repo sync # allow to sync from evilmibm/cackle
# => this worked fine; local repo matches evilmibm/cackle:master
gh repo sync --source vilmibm/cackle # attempt to sync from the fork
# => claims to have succeeded, but local repo state has not changedhalf-completed force sync
I prepared a branch with conflicting changes and saw the expected "can't sync" error; but then when I used force it seemed to work but I do see an opaque git error:
gh repo sync -bevilmibm-patch-1
can't sync because there are diverging changes, you can use `--force` to overwrite the changes
gh repo sync -bevilmibm-patch-1 --force
exit status 128
git log
# => see that I am on evilmibm-patch-1 branch with expected changes; unsure what the error is but it makes me afraid
gh repo sync
✓ Synced .:master from evilmibm/cackle:master
# => claims to succeed...but still on evilmibm-patch-1 branch. nothing has changed.
pkg/cmd/repo/sync/sync.go
Outdated
| return err | ||
| } | ||
| } else { | ||
| err = git.Checkout([]string{"--track", fmt.Sprintf("%s/%s", remote, branch)}) |
There was a problem hiding this comment.
This should ensure that if there are multiple remotes with the same branch name we will checkout the correct one.
There was a problem hiding this comment.
Shouldn't the invocation be: git checkout <branch> --track <remote>/<branch>? It looks like the local branch argument is missing
There was a problem hiding this comment.
According to the docs (https://git-scm.com/docs/git-checkout#Documentation/git-checkout.txt---track) the name to use for the local branch will be automatically determined.
vilmibm
left a comment
There was a problem hiding this comment.
ran through some QA and everything worked well ✨ awesome work
mislav
left a comment
There was a problem hiding this comment.
Implementation looks good! I suggested a bunch of UI/docs changes that I would ideally like to see before this lands.
One note about the overall functionality: if this commands is designed to sync a single branch from one repository to another, wouldn't repo sync be a misnomer? The command name sounds like it sync repositories with each other, but all it does is it sync a single branch with its upstream equivalent. I wonder if the name might mislead people into misinterpreting what this command actually does. But I don't feel very strongly about this concern; just thinking out loud.
pkg/cmd/repo/sync/sync.go
Outdated
| return err | ||
| } | ||
| } else { | ||
| err = git.Checkout([]string{"--track", fmt.Sprintf("%s/%s", remote, branch)}) |
There was a problem hiding this comment.
Shouldn't the invocation be: git checkout <branch> --track <remote>/<branch>? It looks like the local branch argument is missing
pkg/cmd/repo/sync/sync.go
Outdated
| } | ||
| } | ||
| if startBranch != branch { | ||
| err = git.Checkout([]string{startBranch}) |
There was a problem hiding this comment.
Isn't this covered by one of the above git.Checkout?
There was a problem hiding this comment.
Not sure I understand the question. The first git.Checkout is to checkout the branch to sync and then this git.Checkout is to switch back to the initial branch the user was on. I didn't want to assume that the user wanted to switch to the branch that was being sync'ed.
There was a problem hiding this comment.
Ah I've missed that detail. We do not have to switch branches just to update a non-current branch to another ref: there is git update-ref for that! The benefit of not switching branches unnecessarily is that the filesystem needs fewer writes (since the working copy is not being updated) and git reflog is cleaner, which benefits tooling. I'll open a PR to address this.
|
@mislav Thanks for the thorough review! I addressed/commented on your concerns. Regarding the name of the command, do you have better idea? I think |
I'm fine with |
mislav
left a comment
There was a problem hiding this comment.
Looks great!
I think we might have discussed this in a meeting in the past, but do you also envision this command being able to sync 3 repos, i.e. local - remote - parent in a single go in the future? I wonder whether people will want to sync their merge branch in their remote fork but also in the local checkout at the same time, and right now it sounds like they will have to make 2 separate repo sync invocations.
| return git.HasLocalBranch(branch) | ||
| } | ||
|
|
||
| func (g *gitExecuter) IsAncestor(ancestor, progeny string) (bool, error) { |
|
@mislav I don't see this command becoming a swiss army knife type of command and I would like to keep it specific to syncing branches, this could include pruning merged PR branches, and syncing all local branches in the future. I think the main challenge is that the behavior when invoked for a local repo vs a remote repo can get out of sync very fast since we have lots of control over a local repo as opposed to a remote one. In the future when we add features we need to be cognizant of that and think through what the behavior might look like for remote repos or make the features local repo specific. We purposefully skipped the feature of syncing 3 repos to see if our users actually wanted it, so you are correct that as of now it will have to be two separate invocation of |
|
Just tried this out (I’m a little behind) and this is SO GOOD. Thank you! |

This PR adds the
repo synccommand. The command allows syncing between two repositories, referred to asdestination repositoryandsource repository, where changes from thesource repositoryare synced to thedestination repository. When adestination repositoryis not specified by an argument the current local directory is chosen as thedestination repository. The command will try to smartly pick thesource repositorybased on thedestination repositorybut it can also be specified using the--sourceflag. By default thesource repositorydefault branch will be synced but can be overridden with the--branchflag.Additionally this PR adds in the
counterfeiterlibrary as an experiment with generating test doubles for interfaces to see if we like it as an alternative to how we are writing tests now.Examples syncing a local repo

Examples syncing a remote repo

Example trying to sync a remote repo that is not a fork

Example trying to sync a remote repo with diverging commits from parent repo

Fixes #444