On Fri, 2016-10-28 at 15:00 -0700, Junio C Hamano wrote: > Let me see if I understood your scenario correctly. > > Suppose we start from this history where 'O' are common, your victim > has a 'Y' branch with two commits that are private to it, as well as > a 'X' branch on which it has X1 that it previously obtained from the > server. On the other hand, the server does not know about Y1 or Y2, > and it added one commit X2 to the branch 'x' the victim is > following: > > victim server > > Y1---Y2 > / > ---O---O---X1 ---O---O---X1---X2 > > Then when victim wants to fetch 'x' from the server, it would say > > have X1, have Y2, have Y1, have O > > and gets told to shut up by the server who heard enough. The > histories on these two parties will then become like this: > > > victim server > > Y1---Y2 > / > ---O---O---X1---X2 ---O---O---X1---X2 Then the server generates a commit X3 that lists Y2 as a parent, even though it doesn't have Y2, and advances 'x' to X3. The victim fetches 'x': victim server Y1---Y2---- (Y2) / \ \ ---O---O---X1---X2---X3 ---O---O---X1---X2---X3 Then the server rolls back 'x' to X2: victim server Y1---Y2---- / \ ---O---O---X1---X2---X3 ---O---O---X1---X2 And the victim pushes: victim server Y1---Y2---- Y1---Y2---- / \ / \ ---O---O---X1---X2---X3 ---O---O---X1---X2---X3 Now the server has the content of Y2. If the victim is fetching and pulling a whole "directory" of refs, e.g: fetch: refs/heads/*:refs/remotes/server1/* push: refs/heads/for-server1/*:refs/heads/* then instead of generating a merge commit, the server can just generate another ref 'xx' pointing to Y2, assuming it can entice the victim to set up a corresponding local branch refs/heads/for-server1/xx and push it back. Or if the victim is for some reason just mirroring back and forth: fetch: refs/heads/*:refs/heads/for-server1/* push: refs/heads/for- server1/*:refs/heads/* then it doesn't have to set up a local branch as separate step. Matt