Zulip Chat Archive

Stream: new members

Topic: structures, subtypes, coercions and rw


Antoine Chambert-Loir (Nov 04 2021 at 22:37):

I have two questions that puzzle me.
The context is similar in both, a group G acting on a type X:

variables {G:Type*} [group G] {X:Type*} [mul_action G X]

1) The first one is about is_pretransitive, defined as a structure.
Assume I have H: subgroup G and the hypothesis h: is_pretransitive ↥H X (meaning that Hacts pretransitively on X), as well as two members x y : X.
I want to recover the defining property of is_pretransitive, exists_smul_eq, which expands as ∀ (x y : X), ∃ (g : ↥H), g • x = y, and apply it to xand y, to recover g, but while the following

let z := h.exists_smul_eq,
obtain g,h := z x y,

gives me what I want, namely, g: ↥H and h: g • x = y, the following

obtain g,h := h.exists_smul_eq x y,

returns a cryptic

    invalid field notation,
function 'mul_action.is_pretransitive.exists_smul_eq' does not have explicit argument
with type (mul_action.is_pretransitive ...)

2) Anyway, at that point, I arrive at the following context,

x y:  X
g: H
hgxy: g  x = y
z': T (g  x) = mul_aut.conj g  T x
 T (g  x)  H  T x

but I get coercions ↑g that prevent me to rw z'. Can you explain me what I did wrong, or what goes on?
Thank you !

Ruben Van de Velde (Nov 04 2021 at 22:43):

Can you paste a #mwe? Then people can start playing with the code

Yaël Dillies (Nov 04 2021 at 22:45):

I think I got it. Don't worry, Ruben.

Adam Topaz (Nov 04 2021 at 22:50):

This works for me:

import group_theory.group_action.basic

variables (G X : Type*) [group G] [mul_action G X] (H : subgroup G)
  [mul_action.is_pretransitive H X]

include G X H

example : mul_action H X := infer_instance

example (x y : X) : true :=
begin
  obtain g,hg := mul_action.exists_smul_eq H x y,
  sorry
end

Reid Barton (Nov 04 2021 at 22:50):

For 1), is_pretransitive is a class which makes it awkward to use values of the type directly--you're intended to write---what Adam just wrote.

Reid Barton (Nov 04 2021 at 22:51):

For 2), hard to say without knowing where z' came from

Reid Barton (Nov 04 2021 at 22:54):

I guess that hgxy is about the action of H while z' is about the action of G--are these the same by definition? If so you might be able to use change to massage z' into the form you want

Reid Barton (Nov 04 2021 at 22:55):

or you can rewrite using docs#subgroup.smul_def

Antoine Chambert-Loir (Nov 04 2021 at 22:57):

Ruben Van de Velde said:

Can you paste a #mwe? Then people can start playing with the code

Here it is !

example (H: subgroup G) (T : X  subgroup G)
  (is_conj:  g: G,  x : X, T (g  x) = mul_aut.conj g  (T x))
  (is_generator: supr T = ) : is_pretransitive H X  (x:X), H  T x =    :=
  begin
    intros hHX x,
    apply le_antisymm le_top,
    rw [ is_generator],
    rw supr,
    refine Sup_le _,
    intros K hK, obtain y, hKy⟩:= hK, rw  hKy,
    let z := hHX.exists_smul_eq,
    obtain g,h := z x y, rw  h,
    let z' := is_conj (g:G) x,
    sorry,
  end

Antoine Chambert-Loir (Nov 04 2021 at 23:03):

Reid Barton said:

For 2), hard to say without knowing where z' came from

As you can see on the MWE, I have an hypothesis is_conj: ∀ g: G, ∀ x : X, T (g • x) = mul_aut.conj g • (T x) and I create z' by let z' := is_conj (g:G) x.

Reid Barton (Nov 04 2021 at 23:11):

I think using subgroup.smul_def is the way to go

Antoine Chambert-Loir (Nov 23 2021 at 12:24):

A new question that puzzled me for a few hours :
I need to make sense of something like this :

example (α : Type*) [A : set α] [B : set A] (p : A  Prop) (hp :  (a:A), p a  a  B) :
  { a : A | p a } = { b : B | p b } := sorry,

What I could do is

example (α : Type*) [A : set α] [B : set A] (p : A  Prop) (hp :  (a:A), p a  a  B) :
  { a : A | p a }  B :=
begin
  intros a ha, rw set.mem_set_of_eq at ha, exact hp a ha,
end

but I am stuck of ideas to help me pass from the elementary second example to something that looks like the first one.

Actually, this comes from a more complicated context, group A, B : subgroup A, and ultimately, I will need to apply subgroup.closure to both sets to identify subgroup.closure { a : A | p a } with subgroup.closure { b : B | p ↑b }.

Yaël Dillies (Nov 23 2021 at 12:29):

This looks like you got lost in subtyping hell. Can you give the original problem instead?

Anne Baanen (Nov 23 2021 at 12:35):

Can the first example even be proved? The structure of the two types are different: you have (x : { b : B | p b }).1.1.1 : α but (x : { b : A | p b }).1.1 : α.

Antoine Chambert-Loir (Nov 23 2021 at 12:36):

Yaël Dillies said:

This looks like you got lost in subtyping hell. Can you give the original problem instead?

Sure. I want to prove that the alternating group is simple, and to start with, that it is perfect (commutator (alternating_group α) = ⊤).
I have already proved :

lemma three_cycle_is_commutator -- {α : Type*} [decidable_eq α] [fintype α]
  [h5: 5  fintype.card α] (g : alternating_group α) :
   is_three_cycle (g:perm α)  g  commutator (alternating_group α) :=
begin
  intro hg,
    -- g^2 est conjugué de g : g^2 = h g h⁻¹ , donc hg = [h,g]
  let hg2 := hg.is_three_cycle_sq, -- g^2 is a 3-cycle
  rw  subgroup.coe_mul _ g g at hg2,
  obtain h, hh := alternating_group.is_three_cycle_is_conj h5 hg hg2,
  -- g^2 is conjugate to g ;  hh :  g^2 * h = h * g
  suffices : g = h * g * h⁻¹ * g⁻¹ ,
  { apply subgroup.closure_le_normal_closure ,
    apply subgroup.subset_closure,
    rw set.mem_set_of_eq,
    exact h, g, this.symm⟩},
  exact calc g = (g * g * h) * (h)⁻¹ * g ⁻¹ : by simp
    ... = (h * g) * (h)⁻¹  * g⁻¹  : by rw hh.symm
    ... = h * g * (h)⁻¹ * g⁻¹ : by simp,
end

and I want to combine this with
alternating_group.closure_three_cycles_eq_alternating : closure {σ : perm α | is_three_cycle σ} = alternating_group α
(which is in alternating.lean) to get my result.

Antoine Chambert-Loir (Nov 23 2021 at 12:36):

Anne Baanen said:

Can the first example even be proved? The structure of the two types are different: you have (x : { b : B | p b }).1.1.1 : α but (x : { b : A | p b }).1.1 : α.

No, the types are different, but I need somehow to tell Lean that the two sets are equal, so that they will generate the same stuff afterwards…

Johan Commelin (Nov 23 2021 at 12:37):

This typechecks:

example (α : Type*) [A : set α] [B : set A] (p : A  Prop) (hp :  (a:A), p a  a  B) :
  { a : A | p a } = subtype.val '' { b : B | p b } := sorry

Anne Baanen (Nov 23 2021 at 12:39):

Right, like @Johan Commelin suggested, we need a map to translate closure_three_cycles_eq_alternating, a statement on subgroups of perm α to a statement on subgroups of alternating_group α like your goal and three_cycle_is_commutator.

Johan Commelin (Nov 23 2021 at 12:41):

example (α : Type*) [A : set α] [B : set A] (p : A  Prop) (hp :  (a:A), p a  a  B) :
  { a : A | p a } = subtype.val '' { b : B | p b } :=
begin
  ext a, ha⟩,
  simp only [set.mem_image, set_coe.exists, exists_and_distrib_right, subtype.mk_eq_mk,
    exists_eq_right, subtype.exists, set.mem_set_of_eq, subtype.coe_mk, subtype.val_eq_coe],
  split,
  { intro hpa,
    refine hp _ hpa, hpa⟩, },
  { rintro H1, H2⟩, exact H2 }
end

Anne Baanen (Nov 23 2021 at 12:43):

So what we're actually after is the dual form, subtype.val '⁻¹ {a : A | p a} = {b : B | p B}. Or in group-theoretic language comap (alternating_group α).subtype (closure {σ : perm α | is_three_cycle σ}) = \top.

Johan Commelin (Nov 23 2021 at 12:45):

Every time I see .subtype I think it's a pretty horrible name for the inclusion map.

Johan Commelin (Nov 23 2021 at 12:47):

I'm confused, isn't comap H.subtype H' = ⊤ simply saying that H' contains H?

Johan Commelin (Nov 23 2021 at 12:47):

Wouldn't it be better to write H ≤ H' in that case?

Anne Baanen (Nov 23 2021 at 12:48):

Indeed, that would be the next step towards proving the result :)

Anne Baanen (Nov 23 2021 at 12:51):

At least, I'm thinking of a proof of the lines

calc commutator (alternating_group α)
    = closure (conjugates_of_set _) : rfl
... = comap (alternating_group α).subtype (closure {σ : perm α | is_three_cycle σ}) : sorry
... =  : comap_subtype_eq_top sorry

(with comap_subtype_eq_top exactly what you mentioned)

Anne Baanen (Nov 23 2021 at 12:52):

(Some of these =es can equivalently be replaced s of course.)

Eric Wieser (Nov 23 2021 at 14:00):

Johan Commelin said:

Every time I see .subtype I think it's a pretty horrible name for the inclusion map.

Note that for subalgebra it's called docs#subalgebra.val instead

Johan Commelin (Nov 23 2021 at 14:14):

Which makes sense, I guess. Although I think .incl is even more descriptive.

Eric Wieser (Nov 23 2021 at 14:19):

I think we use that name elsewhere for the inclusion map between two subobjects p1 ≤ p2

Eric Wieser (Nov 23 2021 at 14:19):

docs#submonoid.inclusion?

Johan Commelin (Nov 23 2021 at 14:20):

Right, we want both

Eric Wieser (Nov 23 2021 at 14:40):

I suppose incl and incl_of_le would be reasonable names

Eric Wieser (Nov 23 2021 at 14:41):

Although you could maybe argue that subtype.val should be renamed to subtype.incl too...

Johan Commelin (Nov 23 2021 at 14:43):

The difference is that x.val is dot-notation on a term of a subtype, whereas H.incl is dot-notation on a subgroup (or whatever).
Both are also function-like gadgets. But subtype.val doesn't involve a coe_to_sort, whereas H.incl does.
Maybe set.incl should exist.

Antoine Chambert-Loir (Nov 23 2021 at 15:22):

Your discussion lost me! I'm trying to understand what subtype.val does… Is it the inclusion map from a B (viewed as a subtype of A) to A?

Antoine Chambert-Loir (Nov 23 2021 at 15:37):

Thanks ! Now, to go back to my context, where I have group A and B: subgroup A, it seems that what I need to compare a given subgroup of Bwith another given subgroup of A, such as in

-- does not type - fill in ...
example (A : Type*) [group A] [B : subgroup A] (p : A  Prop) (hp : (a : A), p a  a  B) :
  subgroup.closure ({ a : A | p a }) = ... (subgroup.closure({ b : B | p b})) := sorry

Anne Baanen (Nov 23 2021 at 15:40):

Indeed! And the thing you want to fill for the dots are subgroup.map B.subtype, or what I think will turn out to be easier: put subgroup.comap B.subtype on the left instead.

Anne Baanen (Nov 23 2021 at 15:41):

(Easier means here: "saves one rewrite step", if we did it right.)

Kevin Buzzard (Nov 23 2021 at 16:05):

BTW @Antoine Chambert-Loir [B : subgroup A] should probably be (B : subgroup A) or {B : subgroup A}, as subgroup is not a class so square brackets won't do anything. The point is that 99 times out 100 a type has at most one group structure on it, but certainly it's commonplace that a group can have two subgroups, so subgroup shouldn't be a class.

Antoine Chambert-Loir (Nov 23 2021 at 18:14):

I'm making progress… but don't you find that the following sequence of instructions is absolutely ridiculous ?

example (A : Type*) [group A] (B : subgroup A) (C : subgroup B) (a : A) (ha : a  B) :
  a  map B.subtype C  (⟨a, ha : B)  C :=
begin
  split,
  { intro h,
    obtain x, H, hH := subgroup.mem_map.mp h,
    have : a = ((⟨a, ha : B) : A),
    { apply eq.symm,
      exact set_like.coe_mk a ha, },
    rw this at hH,
    simp only [subgroup.coe_subtype, subgroup.coe_mk] at hH,
    rw this at hH,
    simp only [set_like.coe_eq_coe ] at hH,
    rw  hH, exact H },
  { intro h,
    refine subgroup.mem_map.mpr _,
    use a, ha⟩,
    split,
    exact h,
    simp only [subgroup.coe_subtype, subgroup.coe_mk], }
end

Kevin Buzzard (Nov 23 2021 at 18:20):

example (A : Type*) [group A] (B : subgroup A) (C : subgroup B) (a : A) (ha : a  B) :
  a  map B.subtype C  (⟨a, ha : B)  C :=
by tidy

Kevin Buzzard (Nov 23 2021 at 18:23):

example (A : Type*) [group A] (B : subgroup A) (C : subgroup B) (a : A) (ha : a  B) :
  a  map B.subtype C  (⟨a, ha : B)  C :=
begin
  split,
  { rintro ⟨⟨a, ha⟩, h, rfl⟩,
    exact h },
  { rintro h,
    exact ⟨⟨a, ha⟩, h, rfl },
end

Reid Barton (Nov 23 2021 at 18:25):

I also found by { simp [subgroup.mem_map, set_like.exists], tauto } which may or may not be considered good style

Eric Wieser (Nov 23 2021 at 19:10):

Golfed further:

import group_theory.subgroup.basic
open subgroup

example (A : Type*) [group A] (B : subgroup A) (C : subgroup B) (a : A) (ha : a  B) :
  a  map B.subtype C  (⟨a, ha : B)  C :=
@function.injective.mem_set_image _ _ _ subtype.coe_injective _ a, ha

Antoine Chambert-Loir (Nov 23 2021 at 19:42):

Y'all, you're sorcerers…

Antoine Chambert-Loir (Nov 23 2021 at 19:46):

Would you have a link to a description of what rintro is used, especially withrfl?

Johan Commelin (Nov 23 2021 at 19:49):

Hopefully tactic#rintro or tactic#rcases is helpful (edit: I guess you need to read both :smile:)

Antoine Chambert-Loir (Nov 23 2021 at 19:51):

Thanks ! Meanwhile, I tried entering rintroin the google search window, and guess what?…

Adam Topaz (Nov 23 2021 at 21:31):

Just for fun, here is an incomprehensible version of Kevin's proof ;)

example (A : Type*) [group A] (B : subgroup A) (C : subgroup B) (a : A) (ha : a  B) :
  a  map B.subtype C  (⟨a, ha : B)  C :=
λ⟨⟨_,_⟩,h,rfl⟩,h,λh,⟨⟨a,_⟩,h,rfl⟩⟩

Riccardo Brasca (Nov 23 2021 at 21:36):

⟨a,_⟩ can be golfed to ⟨_,_⟩

Adam Topaz (Nov 23 2021 at 21:37):

That last rfl is doing it's job!

Patrick Massot (Nov 23 2021 at 21:37):

I say ⟨λ⟨⟨_,_⟩,h,rfl⟩,h,λh,⟨_,h,rfl⟩⟩

Kevin Buzzard (Nov 23 2021 at 21:39):

I am surprised this works -- I thought the rfl hack would not work with a lambda in term mode.

Adam Topaz (Nov 23 2021 at 21:40):

And now with even more underscores:
⟨λ⟨⟨_,_⟩,_,rfl⟩,‹_›,λ_,⟨⟨_,_⟩,‹_›,rfl⟩⟩

Riccardo Brasca (Nov 23 2021 at 21:41):

Wow!! I've never really understood what ‹_› means, but it's very nice

Eric Rodriguez (Nov 23 2021 at 21:45):

it's basically just a short way to write by assumption!

Kevin Buzzard (Nov 23 2021 at 21:47):

@Antoine Chambert-Loir here's an example of the rfl hack:

import tactic

open function

variables (X Y Z : Type) (f : X  Y) (g : Y  Z)

-- recall that surjective f := ∀ y : Y, ∃ x : X, f x = y

example (hf : surjective f) (hg : surjective g) :
  surjective (g  f) :=
begin
  intro z,
  -- goal `⊢ ∃ (x : X), (g ∘ f) x = z`
  rcases hg z with y, hy⟩,
  -- `hy : g y = z`
  -- so we have a *formula* for z now, it's g(y)
  rcases hf y with x, hx⟩,
  -- and now `hx : f x = y`
  use x,
  /-
  z : Z
  y : Y
  hy : g y = z
  x : X
  hx : f x = y
  ⊢ (g ∘ f) x = z
  -/
  -- there are now several ways to finish, e.g.
  rw  hy,
  rw  hx,
  -- goal got closed because it's now refl and rw tries this
end

example (hf : surjective f) (hg : surjective g) :
  surjective (g  f) :=
begin
  intro z,
  -- goal `⊢ ∃ (x : X), (g ∘ f) x = z`
  rcases hg z with y, rfl⟩, -- *define* z to be g(y)
  -- goal now `⊢ ∃ (a : X), (g ∘ f) a = g y`
  rcases hf y with x, rfl⟩,
  -- now there are no y's or z's in the local context, just
  /-
  x: X
  ⊢ ∃ (a : X), (g ∘ f) a = g (f x)
  -/
  use x,
  -- goal was rfl so got closed because `use` tries `triv` which tries `refl`
end

Antoine Chambert-Loir (Nov 24 2021 at 13:40):

Little progress, Lean knows that the alternating group is perfect… With coercion hacks showing that I didn't really understand what y'all told me yesterday. See #10253

Johan Commelin (Nov 24 2021 at 14:12):

@Antoine Chambert-Loir What do you think of the following approach?

-- still quite stupid, but maybe not too bad
theorem ok_lemma {G : Type*} [group G] (p : G  Prop) :
  closure {x : closure {g | p g} | p (x : G)} =  :=
begin

end

/-- If n ≥ 5, then the alternating group on n letters is perfect -/
theorem alternating_group_is_perfect (h5 : 5  fintype.card α) : commutator (alternating_group α) =  :=
begin
  suffices : closure {b : alternating_group α | (b : perm α).is_three_cycle} = ,
  { rw [eq_top_iff,  this, subgroup.closure_le],
    intros b hb,
    exact three_cycle_mem_commutator h5 hb, },
  rw [ closure_three_cycles_eq_alternating, ok_lemma],
end

Antoine Chambert-Loir (Nov 24 2021 at 14:18):

Let my try that, thanks!
(On the other hand, @Eric Wieser noted that the ugly_lemma matches submodule.comap_subtype_self and should be put in subgroup/basic.lean (Aside : how to refer to a file of the library or to a function so that it adds a link?)

Eric Wieser (Nov 24 2021 at 14:22):

you can type docs#submodule.comap_subtype_self or file#group_theory/subgroup/basic in Zulip, if that's what you mean

Eric Wieser (Nov 24 2021 at 14:23):

Is ok_lemma at all related to docs#subgroup.closure_closure_coe_preimage?

Johan Commelin (Nov 24 2021 at 14:27):

Eric Wieser said:

Is ok_lemma at all related to docs#subgroup.closure_closure_coe_preimage?

Ugh! That statement is unreadable in the docs :sad:

Johan Commelin (Nov 24 2021 at 14:27):

But I think it is exactly ok_lemma

Eric Wieser (Nov 24 2021 at 14:31):

It would be nice if we could teach doc-gen (or maybe the pretty-printer?) to show unappliedcoe with a type annotation

Antoine Chambert-Loir (Nov 24 2021 at 14:47):

It seems my bersion of subgroup.basic.lean is not recent enough… I tried leanproject get-cache, leanproject up, leanproject pull but nothing happens.…

Johan Commelin (Nov 24 2021 at 14:53):

@Antoine Chambert-Loir Please take these steps:

  1. save and commit whatever you've still open
  2. run git pull
  3. run git merge master
  4. run leanproject get-cache

Johan Commelin (Nov 24 2021 at 14:53):

Here's my own proof:

lemma _root_.subgroup.subtype_injective {G : Type*} [group G] (H : subgroup G) :
  function.injective H.subtype :=
subtype.val_injective

@[simp] lemma _root_.subgroup.map_top {G H : Type*} [group G] [group H] (f : G →* H) :
  subgroup.map f  = f.range :=
by { ext, simp only [iff_self, mem_map, monoid_hom.mem_range, exists_true_left],
  split, { rintro g, -, hg⟩, exact g, hg }, { rintro g, hg⟩, exact g, mem_top _, hg } }

@[simp] lemma _root_.subgroup.map_closure
  {G H : Type*} [group G] [group H] (f : G →* H) (s : set G) :
  subgroup.map f (closure s) = closure (f '' s) :=
begin
  ext h, rw [mem_map], split,
  { rintro g, hg, rfl⟩,
    refine closure_induction hg _ _ _ _,
    { intros h hh, exact subset_closure (set.mem_image_of_mem _ hh) },
    { rw f.map_one, exact one_mem _ },
    { intros h₁ h₂ hh₁ hh₂, rw f.map_mul, exact mul_mem _ hh₁ hh₂ },
    { intros h hh, rw f.map_inv, exact inv_mem _ hh } },
  { intro hh,
    refine closure_induction hh _ _ _ _,
    { rintro _ g, hg, rfl⟩, exact g, subset_closure hg, rfl },
    { exact 1, one_mem _, f.map_one },
    { rintro _ _ g₁, h₁, rfl g₂, h₂, rfl⟩, exact g₁ * g₂, mul_mem _ h₁ h₂, f.map_mul _ _ },
    { rintro _ g, hg, rfl⟩, exact g⁻¹, inv_mem _ hg, f.map_inv _ } }
end

lemma _root_.set.coe_image_subtype_coe {α : Type*} (p : α  Prop) (s : set α)
  (h :  x  s, p x) :
  coe '' {x : subtype p | (x : α)  s} = s :=
begin
  ext a, simp only [exists_prop, set.mem_image, subtype.exists, set.mem_set_of_eq, subtype.coe_mk],
  split, { rintro _, h1, h2, rfl⟩, exact h2 }, { intro ha, exact _, h _ ha, ha, rfl }
end

theorem ok_lemma {G : Type*} [group G] (s : set G) :
  closure {x : closure s | (x : G)  s} =  :=
begin
  apply map_injective (subgroup.subtype_injective _),
  simp only [subgroup.map_closure, subgroup.map_closure, subgroup.map_top, subtype_range,
    subgroup.coe_subtype],
  congr' 1, erw [set.coe_image_subtype_coe], intros g hg, exact subset_closure hg
end

Johan Commelin (Nov 24 2021 at 14:54):

Looks like there's a bunch of missing lemmas. (At least I couldn't find them.)

Eric Wieser (Nov 24 2021 at 14:55):

subgroup.map_top is docs#monoid_hom.range_eq_map

Eric Wieser (Nov 24 2021 at 14:56):

subgroup.map_closure might be docs#subgroup.closure_image

Antoine Chambert-Loir (Nov 24 2021 at 14:56):

This works nicely, without any additional lemma !

/-- If n ≥ 5, then the alternating group on n letters is perfect -/
theorem alternating_group_is_perfect (h5 : 5  fintype.card α) : commutator (alternating_group α) =  :=
begin
  suffices : closure {b : alternating_group α | (b : perm α).is_three_cycle} = ,
  { rw [eq_top_iff,  this, subgroup.closure_le],
    intros b hb,
    exact three_cycle_mem_commutator h5 hb, },
  rw  closure_three_cycles_eq_alternating,
  apply subgroup.closure_closure_coe_preimage ,
end

Antoine Chambert-Loir (Nov 24 2021 at 14:57):

Johan Commelin said:

Antoine Chambert-Loir Please take these steps:

  1. save and commit whatever you've still open
  2. run git pull
  3. run git merge master
  4. run leanproject get-cache

What is the difference with leanproject rebase, which ultimately worked?
(I had done a git stash to preserve my modifications, and a git stash pop afterwards!)

Johan Commelin (Nov 24 2021 at 15:03):

Aah, I didn't yet know about leanproject rebase. But it does almost the same thing under the hood.

Antoine Chambert-Loir (Nov 24 2021 at 15:05):

In fact, I'm not sure, I had an ugly git merge to do, but the new PR is done !

Antoine Chambert-Loir (Nov 24 2021 at 15:19):

Is it reasonable that I merge 232 commits into master ?
It seems I should rather revert my previous commit…

Johan Commelin (Nov 24 2021 at 15:25):

Yeah, that doesn't sound good.

Johan Commelin (Nov 24 2021 at 15:25):

The merge should rather go in the other direction

Antoine Chambert-Loir (Nov 24 2021 at 15:30):

This is what I think too.
I tried to do a revert, but that didn't change anything.

Julian Berman (Nov 24 2021 at 15:34):

(I think GitHub diff is just confused possibly, looking at and merging the branch locally it looks fine to me)

Ruben Van de Velde (Nov 24 2021 at 15:34):

What's your branch called?

Eric Wieser (Nov 24 2021 at 15:39):

It sounds like you made this classic mistake:

  • git rebase
  • git push, which errors saying that upstream has diverged
  • git pull (the mistake)

After a rebase, you have to git push -f, not git pull

Antoine Chambert-Loir (Nov 24 2021 at 15:40):

So now, what should I do ?
I have tried to revert to the earlier stuff (and I have a copy of the files in their correct versions).

Eric Wieser (Nov 24 2021 at 15:43):

What do you mean by "revert"?

Eric Wieser (Nov 24 2021 at 15:43):

do you mean git revert or git reset?

Eric Wieser (Nov 24 2021 at 15:44):

revert is not "undo the git action I just did", it's "create a new commit that restores the files to how they were before the action I just did, on top of that action"

Antoine Chambert-Loir (Nov 24 2021 at 15:45):

I meant revert.…

Eric Wieser (Nov 24 2021 at 15:47):

git reset --hard THE_BAD_MERGE_COMMIT^ should get you back to where you were before the merge (and discard your local changes)

Eric Wieser (Nov 24 2021 at 15:47):

You might want to stash before that

Kevin Buzzard (Nov 24 2021 at 15:48):

why not just make the PR and see what happens before doing anything drastic?

Julian Berman (Nov 24 2021 at 15:48):

bors squashes commits though no Eric? So yeah there's a bunch of noise there but technically it should be fine no? I think you can probably get the diff un-confused even by just pushing an empty commit, or if not just opening a new PR?

Ruben Van de Velde (Nov 24 2021 at 15:48):

I would generally not suggest reset --hard to someone who doesn't know what that does :)

Eric Wieser (Nov 24 2021 at 15:48):

Kevin Buzzard said:

why not just make the PR and see what happens before doing anything drastic?

The best time to unbork git history is immediatey after you bork it

Eric Wieser (Nov 24 2021 at 15:49):

Otherwise you build actual work on top of it and then you're in trouble

Antoine Chambert-Loir (Nov 24 2021 at 15:49):

Kevin Buzzard said:

why not just make the PR and see what happens before doing anything drastic?

Nothing is really drastic, I have copies of the two files which I have modified.

Kevin Buzzard (Nov 24 2021 at 15:49):

then why not just make a new branch off master and copy-paste the files in :-)

Kevin Buzzard (Nov 24 2021 at 15:49):

that's what I usually do ;-)

Eric Wieser (Nov 24 2021 at 15:50):

There's no need to use a new branch; just git reset --hard origin/master and paste the files in

Eric Wieser (Nov 24 2021 at 15:50):

That way you can reuse the existing PR

Eric Wieser (Nov 24 2021 at 15:51):

Eric Wieser said:

git reset --hard THE_BAD_MERGE_COMMIT^ should get you back to where you were before the merge (and discard your local changes)

I retract this comment, it looks like you added extra commits after you made the offending merge in e5552fd2add5b8c1b157345c525484617b36d1a2, so the cleanup is much harder.

Antoine Chambert-Loir (Nov 24 2021 at 15:52):

All the commits that came afterwards were inoccuous.

Eric Wieser (Nov 24 2021 at 15:53):

Then probably the quickest recovery is:

git reset --hard d1ca2d4c03cff5087afa52545b2f35bfd7449a0b

# paste back over your files and check if anything changed that you weren't expecting, and commit them

git push --force

Eric Wieser (Nov 24 2021 at 15:54):

Perhaps leanproject rebase should have some heavy warnings, since using it without understanding a git rebase that well gets you in this trap.


Last updated: Dec 20 2023 at 11:08 UTC