mirror of
https://gerrit.googlesource.com/git-repo
synced 2024-12-21 07:16:21 +00:00
Change DWIMery hack for dealing with rewound remote branch
The trick of looking at the reflog for the remote tracking branch and only going back one commit works some of the time, but not all of the time. Its sort of relying on the fact that the user didn't use `repo sync -n` or `git fetch` to only update the tracking branches and skip the working directory update. Doing this right requires looking through the history of the SHA-1 source (what the upstream used to be) and finding a spot where the DAG diveraged away suddenly, and consider that to be the rewind point. That's really difficult to do, as we don't have a clear picture of what that old point was. A close approximation is to list all of the commits that are in HEAD, but not the new upstream, and rebase all of those where the committer email address is this user's email address. In most cases, this will effectively rebase only the user's new original work. If the user is the project maintainer and rewound the branch themselves, and they don't want all of the commits they have created to be rebased onto the new upstream, they should handle the rebase on their own, after the sync is complete. Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
parent
d1f70d9929
commit
8ad8a0e61d
68
project.py
68
project.py
@ -708,28 +708,28 @@ class Project(object):
|
|||||||
syncbuf.later1(self, _doff)
|
syncbuf.later1(self, _doff)
|
||||||
return
|
return
|
||||||
|
|
||||||
if merge == rev:
|
# If the upstream switched on us, warn the user.
|
||||||
try:
|
|
||||||
old_merge = self.bare_git.rev_parse('%s@{1}' % merge)
|
|
||||||
except GitError:
|
|
||||||
old_merge = merge
|
|
||||||
if old_merge == '0000000000000000000000000000000000000000' \
|
|
||||||
or old_merge == '':
|
|
||||||
old_merge = merge
|
|
||||||
else:
|
|
||||||
# The upstream switched on us. Time to cross our fingers
|
|
||||||
# and pray that the old upstream also wasn't in the habit
|
|
||||||
# of rebasing itself.
|
|
||||||
#
|
#
|
||||||
|
if merge != rev:
|
||||||
syncbuf.info(self, "manifest switched %s...%s", merge, rev)
|
syncbuf.info(self, "manifest switched %s...%s", merge, rev)
|
||||||
old_merge = merge
|
|
||||||
|
|
||||||
if rev == old_merge:
|
# Examine the local commits not in the remote. Find the
|
||||||
upstream_lost = []
|
# last one attributed to this user, if any.
|
||||||
else:
|
#
|
||||||
upstream_lost = self._revlist(not_rev(rev), old_merge)
|
local_changes = self._revlist(
|
||||||
|
not_rev(merge),
|
||||||
|
HEAD,
|
||||||
|
format='%H %ce')
|
||||||
|
|
||||||
if not upstream_lost and not upstream_gain:
|
last_mine = None
|
||||||
|
cnt_mine = 0
|
||||||
|
for commit in local_changes:
|
||||||
|
commit_id, committer_email = commit.split(' ', 2)
|
||||||
|
if committer_email == self.UserEmail:
|
||||||
|
last_mine = commit_id
|
||||||
|
cnt_mine += 1
|
||||||
|
|
||||||
|
if not local_changes and not upstream_gain:
|
||||||
# Trivially no changes caused by the upstream.
|
# Trivially no changes caused by the upstream.
|
||||||
#
|
#
|
||||||
return
|
return
|
||||||
@ -738,25 +738,24 @@ class Project(object):
|
|||||||
syncbuf.fail(self, _DirtyError())
|
syncbuf.fail(self, _DirtyError())
|
||||||
return
|
return
|
||||||
|
|
||||||
if upstream_lost:
|
if cnt_mine < len(local_changes):
|
||||||
# Upstream rebased. Not everything in HEAD
|
# Upstream rebased. Not everything in HEAD
|
||||||
# may have been caused by the user.
|
# was created by this user.
|
||||||
#
|
#
|
||||||
syncbuf.info(self,
|
syncbuf.info(self,
|
||||||
"discarding %d commits removed from upstream",
|
"discarding %d commits removed from upstream",
|
||||||
len(upstream_lost))
|
len(local_changes) - cnt_mine)
|
||||||
|
|
||||||
branch.remote = rem
|
branch.remote = rem
|
||||||
branch.merge = self.revision
|
branch.merge = self.revision
|
||||||
branch.Save()
|
branch.Save()
|
||||||
|
|
||||||
my_changes = self._revlist(not_rev(old_merge), HEAD)
|
if cnt_mine > 0:
|
||||||
if my_changes:
|
|
||||||
def _dorebase():
|
def _dorebase():
|
||||||
self._Rebase(upstream = old_merge, onto = rev)
|
self._Rebase(upstream = '%s^1' % last_mine, onto = rev)
|
||||||
self._CopyFiles()
|
self._CopyFiles()
|
||||||
syncbuf.later2(self, _dorebase)
|
syncbuf.later2(self, _dorebase)
|
||||||
elif upstream_lost:
|
elif local_changes:
|
||||||
try:
|
try:
|
||||||
self._ResetHard(rev)
|
self._ResetHard(rev)
|
||||||
self._CopyFiles()
|
self._CopyFiles()
|
||||||
@ -1141,11 +1140,11 @@ class Project(object):
|
|||||||
def _gitdir_path(self, path):
|
def _gitdir_path(self, path):
|
||||||
return os.path.join(self.gitdir, path)
|
return os.path.join(self.gitdir, path)
|
||||||
|
|
||||||
def _revlist(self, *args):
|
def _revlist(self, *args, **kw):
|
||||||
cmd = []
|
a = []
|
||||||
cmd.extend(args)
|
a.extend(args)
|
||||||
cmd.append('--')
|
a.append('--')
|
||||||
return self.work_git.rev_list(*args)
|
return self.work_git.rev_list(*a, **kw)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _allrefs(self):
|
def _allrefs(self):
|
||||||
@ -1270,7 +1269,10 @@ class Project(object):
|
|||||||
self.update_ref('-d', name, old)
|
self.update_ref('-d', name, old)
|
||||||
self._project.bare_ref.deleted(name)
|
self._project.bare_ref.deleted(name)
|
||||||
|
|
||||||
def rev_list(self, *args):
|
def rev_list(self, *args, **kw):
|
||||||
|
if 'format' in kw:
|
||||||
|
cmdv = ['log', '--pretty=format:%s' % kw['format']]
|
||||||
|
else:
|
||||||
cmdv = ['rev-list']
|
cmdv = ['rev-list']
|
||||||
cmdv.extend(args)
|
cmdv.extend(args)
|
||||||
p = GitCommand(self._project,
|
p = GitCommand(self._project,
|
||||||
@ -1280,7 +1282,9 @@ class Project(object):
|
|||||||
capture_stderr = True)
|
capture_stderr = True)
|
||||||
r = []
|
r = []
|
||||||
for line in p.process.stdout:
|
for line in p.process.stdout:
|
||||||
r.append(line[:-1])
|
if line[-1] == '\n':
|
||||||
|
line = line[:-1]
|
||||||
|
r.append(line)
|
||||||
if p.Wait() != 0:
|
if p.Wait() != 0:
|
||||||
raise GitError('%s rev-list %s: %s' % (
|
raise GitError('%s rev-list %s: %s' % (
|
||||||
self._project.name,
|
self._project.name,
|
||||||
|
Loading…
Reference in New Issue
Block a user