мое старое имя пользователя git останется автором после того, как я "раздавлю и объединю" свой код? - PullRequest
0 голосов
/ 01 мая 2019

У меня возникла эта проблема.

У меня есть код, где я сделал около 30 коммитов ...

при коммите 28 Я понял, что неправильно ввел свое имя пользователя, поэтому я обновил его до git config --global user.name

Я пытаюсь избежать перебазирования всех предыдущих коммитов, и мне интересно, если я сделаю squash and merge с использованием github.com из их пользовательского интерфейса, все ли мои предыдущие 30 коммитов должны быть едины, а затем должны быть адресованы моим исправленным имя пользователя?

Что если кто-то использует команду annotate? появится ли мое имя пользователя с опечатками или мое окончательное имя пользователя?

Ответы [ 2 ]

1 голос
/ 01 мая 2019

TL; DR

Как отметил Тим Бигелайзен, автор и коммиттер коммита Git является частью самого коммита, и существующие коммиты с неверным адресом не изменятся.Однако вы можете остановить , используя их, и это то, что git merge --squash позволяет.Следовательно, ответ будет: да, это может решить проблему и нет, это не решит проблему , в зависимости от того, как вы на это смотрите и что делаете во время и после момента, когда вы делаете коммит git merge --squash.

По сути, после сквош-слияния вы просто удаляете ветку, на которой вы сделали эти 30 коммитов.Возможно, вам придется удалить его из двух мест: ваш Git на вашем компьютере и Git на GitHub (который, по-видимому, в некотором роде ваш, но в некотором роде - в конце концов, именно GitHub контролируют его).

Long

Вы упомянули:

, используя github.com из их пользовательского интерфейса

Когда вы работаете с Git из командыстрока (в Windows, Linux, MacOS и т. д.), вы обычно начинаете с клонирования репозитория откуда-то: например,

$ git clone https://github.com/path/to/repo.git
$ cd repo

(хотя я предпочитаю ssh://git@github.com/... URL).В настоящее время существует два Git-репозитория: один на GitHub, а другой локально на вашей собственной машине.

Squashing, fetch, push и множественные Git-репозитории в целом

В общем, здесь есть две вещи, которые нужно знать: как работает git merge --squash, и как эти два разных Gits общаются и делятся коммитами.В частности, в этом есть две части, независимо от того, как вы это делаете: сначала вы сделаете один новый коммит, затем вы будете использовать git push или git fetch до перевод новый коммит (и, возможно, старый коммит или нет) между двумя отдельными Gits.

Любые коммиты, которые вы делаете на на вашем компьютере, используя ваш Git, используйте настройкивы сделали на своем компьютере - но если вы используете веб-интерфейс на GitHub и нажимаете там различные кнопки, вы используете их машины для коммитов в их репозитории Git, которые будут использовать настройки , которые они сохранили для вас.Следовательно, если вы перейдете к кнопке с боковой выпадающей стрелкой, которая позволяет выбирать между слияние , rebase-and-merge и squash-and-merge выберите любой из этих трех и щелкните по нему, их Git делает новый коммит в их Git-репозитории, и все настройки, которые вы установили в своем собственном Git на своем компьютере, не имеют значения.

Вы можете сделать git merge --squash на своем собственном компьютере, а затем использовать git push, чтобы вы сделали коммиты локально и только затем отправили их на другой Git.Независимо от того, когда и когда делать это, зависит только от вас.

Некоторые сведения о создании любого нового коммита

Вы начинаете с выбора некоторого имени ветки и некоторого коммита, который должен быть включен.либо явно запустив:

git checkout somebranch

, либо неявным образом из-за того, что вы сделали это в какой-то момент раньше, так что в любом случае, в этом конкретном репозитории, вы сейчас находитесь на ветке somebranch, который по определению имеет последний, или tip , коммит:

...--o--o--o  <-- somebranch (HEAD)

Каждый коммит имеет какой-то большой уродливый хеш-идентификатор, который означает этот конкретный коммит: любой GitХранилище может сразу сказать, есть ли у него эта фиксация, и если у нее есть эта фиксация по этому хэш-идентификатору, у него есть эта точная фиксация .Все Gits по всему миру согласны: коммит с этим содержимым - с моментальным снимком, с этим именем пользователя и адресом электронной почты, с этими отметками даты, с этим лог-сообщением и т. Д. - будет иметь , идентификатор хеша, и ни у какого другого коммита никогда не будет этого идентификатора хеша.

Имя somebranch содержит внутри себя идентификатор хеша этого коммита, и вы можете сделать:

git rev-parse somebranch

доувидеть этот хэш-идентификатор.Вы также увидите этот хэш-идентификатор или его сокращенную версию в выходных данных git log и git log --oneline.Этот хэш-идентификатор, хранящийся в этом имени ветви, - это то, как Git знает, что ваша текущая ветвь somebranch заканчивается этим конкретным коммитом.

Внутри этого коммита находится хэш-идентификатор его непосредственного предшественника или parent коммит.Вот как Git может перейти от коммита tip к коммиту на шаг раньше.Внутри родителя находится хеш-идентификатор деда текущего коммита, поэтому от родителя Git может перейти к дедушке.У бабушки и дедушки есть еще один хэш-идентификатор, поэтому Git может ходить к прабабушке и так далее.Эта цепочка хеш-идентификаторов позволяет Git находить все коммиты, начиная с конца и работая в обратном направлении.

Следовательно, если у нас есть цепочка коммитов, оканчивающаяся, скажем, на коммит с хешем H:

... <-grandparent <-parent <-H   <-- branch-name

и мы собираемся сделать новый коммит, способ, которым Git на самом деле делает новый коммит состоит в том, чтобы упаковать моментальный снимок коммита с указанием имени автора и сообщения журналаи так далее, установите parent hash в H и запишите его.Поскольку содержимое этого коммита уникально - родительский хеш H вместе с меткой времени, добавляемой Git, которая сообщает, какая именно секунда была при создании нового коммита, убедитесь, что он будет уникальным - новый коммит получаетновый уникальный идентификатор хеша.Давайте назовем это I:

... <-parent <-H <-I

Теперь все, что Git должен сделать, это записать хэш-идентификатор нового коммита I в имя ветви, так что коммит I является подсказкой.

Другими словами, Git начинается в конце каждой ветви и работает в обратном направлении.Так что этот вид цепочки позволяет Git находить все коммиты, которые содержатся в этой ветке .Некоторые коммиты могут содержаться только в какой-то другой ветви:

       B--C   <-- master
      /
...--A
      \
       D--...--G--H--I   <-- somebranch (HEAD)

Здесь есть несколько коммитов, скажем, где-то около 30 коммитов, которые только на somebranch, с двумя коммитами, которые только на master и многими коммитами на обе ветви.(Если вы посчитаете D-E-F-G-H-I-J, есть место только для 7 коммитов; ну, давайте просто притворимся, что где-то между D и H :-)) есть куча новых букв.Коммиты с D по H имеют неправильное имя автора, а коммиты I и J имеют правильное имя.Наш план сейчас состоит в том, чтобы прекратить использование всех D до H полностью.

Использование git merge --squash

Давайте посмотрим, как именно git merge --squash действительно работает,По сути, он делает то же самое, что и обычное слияние, кроме как в самом конце.Регулярное слияние начинается с определения, какой коммит является лучшим shared коммитом, т. Е. Лучшим коммитом, который находится на обеих ветвях.Этот лучший общий коммит представляет собой базу слияния из двух ветвей.

Мы извлекаем одну ветку, а затем называем другую в нашей команде git merge --squash:

$ git checkout master                   # note: this attaches HEAD to master
$ git merge --squash somebranch

Git проверяет цепочки коммитов, которые составляют историю, которая находится в этом хранилище, чтобы найти лучший общий коммит.В нашем случае, когда история master ведет к фиксации A, а история somebranch также ведет к фиксации A, коммит A является наилучшим общим коммитом.(Все коммиты до A также доступны: они не так хороши, как A.)

Далее Git сравнивает снимок в базе слияния - в коммитеA - для этого в нашей текущей ветке tip commit C:

git diff --find-renames <hash-of-A> <hash-of-C>   # what we changed in master

Он делает то же самое, чтобы выяснить, что «они» (на самом деле, мы) изменили в другой ветке:

git diff --find-renames <hash-of-A> <hash-of-I>   # what they changed

Затем Git делает все возможное, чтобы объединить эти два набора изменений, применяя объединенные изменения к снимку с коммита A.Если все идет хорошо, эта комбинация является снимком для использования.Если все пойдет не так, Git прекратит конфликт слияния и получит помощь от пользователя, чтобы исправить и завершить его.

(Подробнееточно, ваш Git сделает это.Сетевой Git на GitHub просто скажет извините, я не могу этого сделать и даже не позволю вам вообще начать слияние - они проверяют перед тем, как сделать кнопку слияния нажатой.Он немного отличается от обычного Git, поскольку не позволяет вам взаимодействовать с ним для разрешения конфликтов.У людей GitHub есть настольный клиент, но я никогда не использовал его;Я не знаю, является ли это оболочкой из командной строки Git или чем-то более причудливым.)

Здесь мы будем предполагать, что либо все идет хорошо, либо вы исправили все конфликты и запустите git merge --continue илиgit commit для завершения слияния.Git теперь делает коммит, у которого вместо обычного одного родителя двух родителей:

       B--C--------------J   <-- master (HEAD)
      /                 /
...--A                 /
      \               /
       D--...--G--H--I   <-- somebranch

Новый коммит переходит на ветку master, потому что HEAD прикреплен к master (из-за нашего git checkout master выше).Новый коммит J указывает на коммит C, коммит, который был вершиной master;но он также указывает на фиксацию I, фиксацию которой все еще составляет верхушка somebranch.Коммиты C и I теперь оба на master, из-за этого дополнительного второго родителя, который ведет к фиксации I.

Когда вы используете git merge --squash, ключевое отличие состоит в том, чтоНовый коммит J не имеет второго родителя:

       B--C---------------J   <-- master (HEAD)
      /
...--A
      \
       D--...--G--H--I   <-- somebranch

Все остальное точно так же: снимок для J, автора и коммиттера (устанавливается любым Gitфактически делает commit J), отметку времени (аналогично) и родительский хэш-идентификатор commit C.Но нет второго родителя для нового коммита J.

Если вы хотите, чтобы коммиты D через I исчезли, вы просто удалите ветвь somebranch. имя somebranch - это то, как ваш Git находит эти коммиты: он начинает с хеш-идентификатора I из имени somebranch, затем использует I для поиска H, H, чтобы найти G, и так далее, все вниз по линии, пока не достигнете A.Имя somebranch позволит вам достичь A, но и имя master.Таким образом, удаление name somebranch делает коммиты D через I исчезающими из поля зрения.В конце концов - обычно через 30 дней или около того - ваш Git будет собирать мусор этих коммитов.

Но, опять же, вы упомянули "использование [the] github.com ... UI".Если вы собираетесь это сделать, вы должны сначала отправить коммиты с D через I на GitHub, или, возможно, вы уже отправили их.

Передача коммитов с помощью git fetchи git push

Вы можете в любое время подключить один Git к другому Git и либо получить (fetch), либо отправить (push) коммиты с другого Git или на него.Затем из Git вашего собственного компьютера вы получаете коммиты GitHub-Git с git fetch и отправляете коммиты на , которые Git с git push.

Реальный протокол передачи имеет многонебольших тонкостей, но все начинается довольно просто: ваш Git и их Git ведут беседу, в которой один рассказывает другому о хеш-идентификаторах коммитов, которые он может отправить, а другой говорит: У меня есть этоодин уже или о, я возьму этот .Итак, предположим, что у вас есть:

...--A
      \
       D--...--G--H--I   <-- somebranch (HEAD)

и у них есть:

       B--C   <-- master (HEAD)
      /
...--A

(различные HEAD с являютсяВ конце концов, это два разных Гита.Если вы подключите ваш Git к их git push origin somebranch, ваш Git будет перечислять ваши хэш-идентификаторы коммитов I, H и т. Д. Обратно в A.Когда ваш Git достигнет хеш-идентификатора для A, они скажут: хорошо, хватит, у меня он есть! Затем ваш Git соберет коммиты с D через H и отправит их через.

В конце ваш Git добавляет окончательный запрос: Пожалуйста, укажите название вашей ветви somebranch, чтобы запомнить хеш-код I. Их Git не имеет a somebranch пока, так что они в порядке с этим и делают это, и ваш мерзавец и их мерзавец сделаны, и вы отключаетесь.

Вы можете либо до, либо после этого также запустить git fetch origin. Вот ваш Git вызывает их Git, но на этот раз их Git является отправителем. Они отправят вам совершить хэш C, сказав: У моего master есть этот хеш, у вас есть коммит C? Если вы этого не сделаете, они также предложат B, а затем A, который у вас есть.

Если вы запускаете git fetch origin master, ваш Git будет принимать только те коммиты, которые они имеют на своих master, которых у вас нет вообще, но с git fetch origin ваш Git будет принимать любые коммиты, которых у вас нет из любых имен их ветвей: они перечислят их все вместе с хэш-идентификаторами коммитов, а ваш Git может и будет жадным и попросит их всех.

В любом случае, в конце этого процесса нет отдельного вежливого запроса: ваш Git просто говорит: ОК, теперь я знаю, что их master идентифицирует коммит C, поэтому я обновлю my origin/master, чтобы он идентифицировал commit C. Итак, вы получите это в своем хранилище:

       B--C   <-- origin/master
      /
...--A   <-- master
      \
       D--...--G--H--I   <-- somebranch (HEAD)

Ваш собственный master теперь на два коммита позади их master, так что теперь вы можете запустить:

$ git checkout master

, который перемещает HEAD в master:

       B--C   <-- origin/master
      /
...--A   <-- master (HEAD)
      \
       D--...--G--H--I   <-- somebranch

и затем запустите:

git merge origin/master

(или git merge --ff-only origin/master). Это замечает, что общей базой слияния между вашим master и вашим origin/master является коммит A - вершина master - поэтому он выполняет то, что Git называет операция быстрой пересылки , а не настоящее слияние: он просто проверяет фиксацию C напрямую и перемещает туда master:

       B--C   <-- master (HEAD), origin/master
      /
...--A
      \
       D--...--G--H--I   <-- somebranch

Обратите внимание, что git fetch обновляет ваши origin/* имена в соответствии с их Git, в то время как git push заканчивается вежливыми запросами в форме: Пожалуйста, установите ваши фактические имена веток для этих конкретных коммитов . Это означает, что вы всегда можете запустить git fetch: это никак не повлияет на ваши ветви. Но иногда вы не можете достичь простого git push, поскольку они иногда отказываются менять свои ветви. (Я не буду вдаваться в подробности здесь, так как это уже очень долго, но для этого git push --force: он изменяет вежливый запрос на команду. Им не нужно подчиняться команде, но они вероятно, будет.)

О git pull

Команда git pull - нечто странное в Git. Он запускает git fetch, затем запускает вторую команду Git. Вторая команда обычно git merge. Вы можете сказать ему использовать git rebase вместо этого, либо на разовой основе, либо вообще. Я предпочитаю избегать git pull и запускать эти две команды отдельно, потому что это позволяет мне посмотреть, что git fetch извлек , прежде чем я выберу любую команду для запуска. Если вы разрешите git pull запустить вторую команду, вы должны выбрать , какую вторую команду использовать до , вы знаете, что на самом деле git fetch выбирает.

Но многие люди используют git pull, поэтому вы должны знать, что он делает. В этом случае это может быть ловушка, как мы увидим.

Допустим, вы сквош-слияние на GitHub

Чтобы сделать сквош-слияние на GitHub, вы должны сначала отправить им все свои somebranch коммиты:

$ git push origin somebranch

У них теперь есть:

       B--C   <-- master (HEAD)
      /
...--A
      \
       D--...--G--H--I   <-- somebranch

в их Git. Теперь вы делаете пул-запрос с помощью веб-интерфейса GitHub и переходите по кликающим кнопкам, выбираете squash-and-merge и нажимаете его:

       B--C----------J   <-- master (HEAD), origin/master
      /
...--A
      \
       D--...--G--H--I   <-- somebranch

Теперь вам нужно удалить somebranch, как на GitHub, так и в вашем собственном репозитории Git . Если вы сделаете это, у вас все будет хорошо: 30 (или сколько угодно) коммитов, которые были и на данный момент остаются, только на somebranch (в обоих Гитах) больше не видны. (Примечание: GitHub стремится немедленно удалить свои копии, в то время как ваш Git ожидает более 30 дней.)

Но если вы или кто-нибудь по этому вопросу, случайно слите somebranch с master, вы теперь получите новый коммит слияния:

       B--C----------J
      /               \
...--A                 K
      \               /
       D--...--G--H--I

Обратите внимание, что любой может совершить эту ошибку в любое время после создания J и до того, как D -through- I исчезнет / станет невидимым.Так как git pull запускает git fetch, а затем git merge, делает эту ошибку легко, используя git pull.

В частности, если вы самостоятельно somebranch и выполняетеgit pull origin master, вы получите именно эту ошибку.К счастью, это легко исправить.Теперь у вас есть это:

       B--C----------J    <-- master
      /               \
...--A                 K   <-- somebranch (HEAD)
      \               /
       D--...--G--H--I

Вам по-прежнему нужно удалить ответвление somebranch, и теперь коммиты D через K невидимы и со временем исчезнут:

$ git checkout master
$ git branch -D somebranch

* * checkout потому что вы не можете удалить ветку, на которой находитесь;-D (как бы верхний регистр) - это способ принудительного удаления, хотя git branch обычно жаловался бы на то, что вы потеряете коммиты D - через- K (что, конечно,идея).

1 голос
/ 01 мая 2019

Имя автора, связанное с коммитом Git, является частью истории коммитов, и поэтому просто изменение вашего имени пользователя с помощью git config изменит , а не , изменит любые коммиты, которые уже существуют в прошлом.Это будет влиять только на коммиты, которые вы сделаете в будущем.Таким образом, это означает, что кому-то, кто ищет коммиты, сделанные под вашим предыдущим именем пользователя, придется использовать это предыдущее имя пользователя в поиске.

Это не рекомендуется, но если вы действительно хотите переписать историю одного или несколькихваши ветки, чтобы изменить автора, затем прочитайте Как изменить автора коммита для одного конкретного коммита? .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...