为什么我的提交历史看起来像这样,我该如何修复它?

Why does my commit history look like this and how can I go about fixing it?

所以在过去的几天里,我一直在试图弄清楚为什么我的 git 提交历史看起来像这样,而我的提交历史并不是像我希望的那样是线性的?我已经尝试了很多方法来试图让这个所谓的 扁平化 但无济于事。

如果有人能提供帮助,我们将不胜感激。

从 git 中的 git log --oneline --graph 命令查看 bash

git log 中查看 SmartGit

这是我在 运行 git rebase 0fa9983894820ac8062a7413188e4ea2bc28089b

之后得到的错误

你的历史是这样的原因是因为你在某个时候创建​​了一个新分支,然后将其合并回去。(或者其他人这样做了。)

如果您正在使用 GitHub,那么这也可能意味着您接受了拉取请求,这相当于合并。 如果是这样,则有一般来说,没有办法解决这个问题。从他们的角度来看,这是一个合理的选择,因为合并比变基更健壮,并且更好地保留作者身份更改:我们只需要忍受更丑陋的日志输出。那样的话,你可以在这里停止阅读了。


我不知道有什么自动更改此设置的方法,但我可以向您展示如何 rebase 按照您想要的方式提交。这涉及重写从错误点一直到 HEAD 的历史记录,创建具有相同内容的不同提交。

但是,我注意到您正在查看的分支不是本地分支,而是您本地副本的原始分支(这里假设通常的 Git 约定)。我理解对干净漂亮的日志输出的渴望,但是,有一个实际的理由不 rebase 旧历史:

Warning: Although it is possible to rebase your commits locally, it is not a good idea to push such changes to a public project. Rebasing your history always causes problems for others with whom you've shared the unmodified history. So, anyone else involved with your project will be hosed.


有了那个警告,这里是:

  1. 首先,复制你的存储库,这样你就有了备份。 (rebase 命令永远不会丢失数据,但如果您不熟悉 rebase 命令,如果您犯了错误或改变了主意,可能很难恢复到已知状态。)
  2. 检查基于origin/master的新分支,因为您不能直接修改它(git checkout -b new-master origin/master)
  3. 接下来,执行 git rebase --interactive <commitish>,其中 <commitish> 标识标记为 "Everything is in working order" (0fa9) 的提交。
  4. rebase 操作现在将在您的编辑器中打开,以供您批准。
  5. 第一行将是名为 "Renamed some of the files" (09ab) 的行。将其操作从 pick 更改为 edit
  6. 保存文件并关闭它。变基操作将开始。
  7. 当 rebase 在第一次提交后停止时,git cherry-pick <commitish> 其中 <commitish> 描述了名为 "Rename backup file ftp.py to ..." 的提交。
  8. git rebase --continue
  9. 验证结果。您会注意到现在每个提交都有不同的 ID,尽管具有相同的描述和相同的内容(差异)。这是因为您编写了 new 历史记录,其中包含 old 更改。提交日期将更改,但作者日期不变。

现在,如果您想用您的新历史影响他人,您可以通过将这些更改推送到您的 origin 存储库来实现:

$ git push --force origin/master

--force 是必需的,因为这将覆盖现有分支,并使由此创建的任何分支无效,包括 所有 贡献者的本地存储库。

看看我丑陋的树:

* 8d61057 (HEAD -> master) file4
*   61795ae Merge branch 'new'
|\  
| * 56f104d file2
* | 2484695 file3
|/  
* ecc3f4f init

请注意 61795ae Merge branch 'new' 没有引入任何新内容,而只是合并提交。

我可以从拆分前的最后一次提交中 rebase 直线恢复我的行李箱。

git rebase ecc3f4f

现在树又直了

* e794681 (HEAD -> master) file4
* b65595a file3
* 3d6ffe9 file2
* ecc3f4f init

说明

克隆您的项目后,我想查看提交以了解冲突。

您重命名了这个备份脚本。

051dae3 Rename backup final ftp.py to backup ftp v.4 (final).py
Backup scripts/backup final ftp.py → Backup scripts/backup ftp v.4 (final).py

但与此同时,在此存储库的另一个克隆中,您将此备份脚本与其他一组 "Python" 文件夹移动到

09abfd7 Renamed some of the files
Backup scripts/backup final ftp.py → Python/Backup scripts/backup final ftp.py

现在要解决此冲突,您必须通过两次提交来清理它。

第一个只是将文件从正确的文件夹中取出到正确名称的错误文件夹中。

8006e70 Renamed some files
Python/Backup scripts/backup final ftp.py → Backup scripts/backup ftp v.4 (final).py

那么你刚刚丢失了带有 "unneeded folder"

的文件
bac2105 Deleted an unneeded folder
deleted Backup scripts/backup ftp v.4 (final).py

基本上,这是一个检查这两个提交的问题,将它们软重置到暂存区,然后将它们全部提交。

然后挑选其余的。您可以克隆 straight master branch here

程序

git clone https://github.com/Lowe-Man/Portfolio

cd Portfolio/

git log --graph --oneline --decorate --all
* de71d41 (HEAD -> master, origin/master, origin/HEAD) Removed a gitignore specifier from the .gitignore file
* f80eb5c Added 'Lecture 26 Files'
* 505478e Added 'Lecture 25 Tuples'
* 632a2f3 Added 'Lecture 23 Dictionaries'
* 990d74e Reorganized/Fixed all of the code/comments on all of the lectures that I have done up to this point
* bb213ac Added 'Lecture 21 Lists'
* ab99b1c Added 'Lecture 19 Print Formatting'
* 3f37ca3 Changed the numbering of the files
* 16e17be Added 'Lecture 16 Strings'
* c654494 Reorganized the repository
* 60b17e4 Added 'Remove Numbers v.1.py'
* e35b6ba Added 'Lecture 14 Numbers'
* bac2105 Deleted an unneeded folder
*   8006e70 Renamed some files
|\  
| * 051dae3 Rename backup final ftp.py to backup ftp v.4 (final).py
* | 09abfd7 Renamed some of the files
|/  
* 0fa9983 Everything is in working order
* dfc9747 Fixed a few if statements
* e183900 Added Countdown Timers and other help to the portfolio
* 2377980 Removed some unnecessary lines of code
* 4172115 Added some new fetures to the script
* 4a7f2d1 Fixed some minor bugs in the code
* 589251c Removed text from a variable
* 93e9742 Finished the backup final ftp script for now
* c5687a3 Added the feature to remove files/folders that are older than a certain age
* 19a495f Removed some blank lines at the bottom of the file
* c2c58c3 Converts the folder to a .tar.bz2 and then deletes the folder
* 6718968 Made some minor changes to the code to increase usability
* b7d6608 Initial commit
git checkout 051dae3

git reset --soft HEAD~

git status
HEAD detached from 051dae3
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  renamed:    Backup scripts/backup final ftp.py -> Backup scripts/backup ftp v.4 (final).py
git checkout 09abfd7

git reset --soft HEAD~

git status
HEAD detached from 09abfd7
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  new file:   Backup scripts/backup ftp v.4 (final).py
  renamed:    Backup scripts/backup final ftp.py -> Python/Backup scripts/backup final ftp.py
  renamed:    Backup scripts/backup ftp v.1.py -> Python/Backup scripts/backup ftp v.1.py
  renamed:    Backup scripts/backup ftp v.2.py -> Python/Backup scripts/backup ftp v.2.py
  renamed:    Backup scripts/backup ftp v.3.py -> Python/Backup scripts/backup ftp v.3.py
  new file:   Python/Backup scripts/backup local.py
  renamed:    Countdown Timers/Countdown Timer (Cleaned).py -> Python/Countdown Timers/Countdown Timer v.2.py
  new file:   Python/Countdown Timers/Countdown Timer v.3 (final).py
  renamed:    Countdown Timers/Coutdown Timer.py -> Python/Countdown Timers/Coutdown Timer (original).py
  renamed:    Countdown Timers/Coutdown Timer (Improved).py -> Python/Countdown Timers/Coutdown Timer v.1.py
  renamed:    Help/How to remove zeros.py -> Python/Help/How to remove zeros.py
  renamed:    Help/Timezone.py -> Python/Help/Timezone.py
  renamed:    Countdown Timers/length.py -> Python/Help/length.py

放弃多余的副本,将正确命名的副本移至 Python 文件夹。

rm 'Python/Backup scripts/backup final ftp.py'

mv 'Backup scripts/backup ftp v.4 (final).py' 'Python/Backup scripts/backup ftp v.4 (final).py'

git add .

git status
HEAD detached from 09abfd7
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  renamed:    Backup scripts/backup ftp v.1.py -> Python/Backup scripts/backup ftp v.1.py
  renamed:    Backup scripts/backup ftp v.2.py -> Python/Backup scripts/backup ftp v.2.py
  renamed:    Backup scripts/backup ftp v.3.py -> Python/Backup scripts/backup ftp v.3.py
  renamed:    Backup scripts/backup final ftp.py -> Python/Backup scripts/backup ftp v.4 (final).py
  new file:   Python/Backup scripts/backup local.py
  renamed:    Countdown Timers/Countdown Timer (Cleaned).py -> Python/Countdown Timers/Countdown Timer v.2.py
  new file:   Python/Countdown Timers/Countdown Timer v.3 (final).py
  renamed:    Countdown Timers/Coutdown Timer.py -> Python/Countdown Timers/Coutdown Timer (original).py
  renamed:    Countdown Timers/Coutdown Timer (Improved).py -> Python/Countdown Timers/Coutdown Timer v.1.py
  renamed:    Help/How to remove zeros.py -> Python/Help/How to remove zeros.py
  renamed:    Help/Timezone.py -> Python/Help/Timezone.py
  renamed:    Countdown Timers/length.py -> Python/Help/length.py

除了我们重命名的所有其他内容之外,感兴趣的分阶段解决方案是:

  renamed:    Backup scripts/backup final ftp.py -> Python/Backup scripts/backup ftp v.4 (final).py

使用相同的消息进行新的提交。

git commit -c ORIG_HEAD

git log --graph --oneline --decorate --all
* 1cc1b2c (HEAD) Renamed some of the files
| * de71d41 (origin/master, origin/HEAD, master) Removed a gitignore specifier from the .gitignore file
| * f80eb5c Added 'Lecture 26 Files'
| * 505478e Added 'Lecture 25 Tuples'
| * 632a2f3 Added 'Lecture 23 Dictionaries'
| * 990d74e Reorganized/Fixed all of the code/comments on all of the lectures that I have done up to this point
| * bb213ac Added 'Lecture 21 Lists'
| * ab99b1c Added 'Lecture 19 Print Formatting'
| * 3f37ca3 Changed the numbering of the files
| * 16e17be Added 'Lecture 16 Strings'
| * c654494 Reorganized the repository
| * 60b17e4 Added 'Remove Numbers v.1.py'
| * e35b6ba Added 'Lecture 14 Numbers'
| * bac2105 Deleted an unneeded folder
| *   8006e70 Renamed some files
| |\  
| | * 051dae3 Rename backup final ftp.py to backup ftp v.4 (final).py
| |/  
|/|   
| * 09abfd7 Renamed some of the files
|/  
* 0fa9983 Everything is in working order
* dfc9747 Fixed a few if statements
* e183900 Added Countdown Timers and other help to the portfolio
* 2377980 Removed some unnecessary lines of code
* 4172115 Added some new fetures to the script
* 4a7f2d1 Fixed some minor bugs in the code
* 589251c Removed text from a variable
* 93e9742 Finished the backup final ftp script for now
* c5687a3 Added the feature to remove files/folders that are older than a certain age
* 19a495f Removed some blank lines at the bottom of the file
* c2c58c3 Converts the folder to a .tar.bz2 and then deletes the folder
* 6718968 Made some minor changes to the code to increase usability
* b7d6608 Initial commit

现在我们已经有效地将提交 051dae38006e70bac2105 合并为 09abfd7 作为新提交 1cc1b2c 这是我的方式认为它应该首先在功能上被提交。

所以剩下的就是从 e35b6ba Added 'Lecture 14 Numbers'

开始挑选树的其余部分
git cherry-pick e35b6ba^..de71d41

git log --graph --oneline --decorate --all
* 0e52036 (HEAD) Removed a gitignore specifier from the .gitignore file
* 1cf948b Added 'Lecture 26 Files'
* 62a1602 Added 'Lecture 25 Tuples'
* aeb7421 Added 'Lecture 23 Dictionaries'
* d47635d Reorganized/Fixed all of the code/comments on all of the lectures that I have done up to this point
* d54141c Added 'Lecture 21 Lists'
* 66174f2 Added 'Lecture 19 Print Formatting'
* 3969da2 Changed the numbering of the files
* 9c4828c Added 'Lecture 16 Strings'
* ce159a3 Reorganized the repository
* 759e08b Added 'Remove Numbers v.1.py'
* 323be27 Added 'Lecture 14 Numbers'
* 1cc1b2c Renamed some of the files
| * de71d41 (origin/master, origin/HEAD, master) Removed a gitignore specifier from the .gitignore file
| * f80eb5c Added 'Lecture 26 Files'
| * 505478e Added 'Lecture 25 Tuples'
| * 632a2f3 Added 'Lecture 23 Dictionaries'
| * 990d74e Reorganized/Fixed all of the code/comments on all of the lectures that I have done up to this point
| * bb213ac Added 'Lecture 21 Lists'
| * ab99b1c Added 'Lecture 19 Print Formatting'
| * 3f37ca3 Changed the numbering of the files
| * 16e17be Added 'Lecture 16 Strings'
| * c654494 Reorganized the repository
| * 60b17e4 Added 'Remove Numbers v.1.py'
| * e35b6ba Added 'Lecture 14 Numbers'
| * bac2105 Deleted an unneeded folder
| *   8006e70 Renamed some files
| |\  
| | * 051dae3 Rename backup final ftp.py to backup ftp v.4 (final).py
| |/  
|/|   
| * 09abfd7 Renamed some of the files
|/  
* 0fa9983 Everything is in working order
* dfc9747 Fixed a few if statements
* e183900 Added Countdown Timers and other help to the portfolio
* 2377980 Removed some unnecessary lines of code
* 4172115 Added some new fetures to the script
* 4a7f2d1 Fixed some minor bugs in the code
* 589251c Removed text from a variable
* 93e9742 Finished the backup final ftp script for now
* c5687a3 Added the feature to remove files/folders that are older than a certain age
* 19a495f Removed some blank lines at the bottom of the file
* c2c58c3 Converts the folder to a .tar.bz2 and then deletes the folder
* 6718968 Made some minor changes to the code to increase usability
* b7d6608 Initial commit

现在我们可以删除旧的master分支,使用这个作为新的master,并强制推送到远程。

git branch -d master

git checkout -b master

git push origin master --force

git log --graph --oneline --decorate --all
* 0e52036 (HEAD -> master, origin/master, origin/HEAD) Removed a gitignore specifier from the .gitignore file
* 1cf948b Added 'Lecture 26 Files'
* 62a1602 Added 'Lecture 25 Tuples'
* aeb7421 Added 'Lecture 23 Dictionaries'
* d47635d Reorganized/Fixed all of the code/comments on all of the lectures that I have done up to this point
* d54141c Added 'Lecture 21 Lists'
* 66174f2 Added 'Lecture 19 Print Formatting'
* 3969da2 Changed the numbering of the files
* 9c4828c Added 'Lecture 16 Strings'
* ce159a3 Reorganized the repository
* 759e08b Added 'Remove Numbers v.1.py'
* 323be27 Added 'Lecture 14 Numbers'
* 1cc1b2c Renamed some of the files
* 0fa9983 Everything is in working order
* dfc9747 Fixed a few if statements
* e183900 Added Countdown Timers and other help to the portfolio
* 2377980 Removed some unnecessary lines of code
* 4172115 Added some new fetures to the script
* 4a7f2d1 Fixed some minor bugs in the code
* 589251c Removed text from a variable
* 93e9742 Finished the backup final ftp script for now
* c5687a3 Added the feature to remove files/folders that are older than a certain age
* 19a495f Removed some blank lines at the bottom of the file
* c2c58c3 Converts the folder to a .tar.bz2 and then deletes the folder
* 6718968 Made some minor changes to the code to increase usability
* b7d6608 Initial commit

通过提供您的源代码,我能够对您当前的存储库执行以下步骤,并牢记@jpaugh 的回答,以便获得与您开始时完全相同的代码。你遇到麻烦的原因 @jpaugh 的回答是因为我们有 remove/remove 必须手动解决的合并冲突。

因为您已经解决了这个合并冲突,我们将按照您第一次解决它的方式进行操作。

抓住你想改变历史的分支。

git checkout origin/master

我们将要 rebase 合并之前的提交。默认情况下,rebase 不保留合并历史记录,因此这将从该提交到您的 origin/master 所在的位置线性重播您的工作。

git rebase 0fa9983

但是我们遇到了一些问题。历史中的合并有一个您已解决的 remove/remove 冲突。让我们添加您在 resolve commit8006e70 和分支 051dae3 中所做的更改,以模拟您在另一个分支之后立即进行更改,而不是并行进行。

git checkout 8006e70 Backup\ scripts/backup\ ftp\ v.4\ \(final\).py
git rm Backup\ scripts/backup\ final\ ftp.py
git rm Python/Backup\ scripts/backup\ final\ ftp.py

所以现在我们要将更改作为新提交提交,但让我们使用 C 标记为其提供与我们要替换的合并提交相同的提交消息。使用我们想要从中获取消息的分支的哈希值。

git commit -C 051dae3

让我们使用 continue 命令继续变基。

git rebase --continue

我们有一个新问题,那就是我们将两个提交合并为一个(合并和分支)。它仍在努力发挥作用,继续调整基数。如果我们在原始的 rebase 命令中使用了 -i 标签,我们可以指示我们应该跳过这个提交,但是这个例子都是命令行。我们将在这里跳过它。它在这里失败了,因为它所做的所有更改都已经发生。我们选择在分支中包含提交消息,而不是简短的 renamed some files 消息,因此当您查看我们的新历史记录时,您的意图就很清楚了。继续并跳过此冲突,允许 rebase 继续历史的其余部分。

git rebase --skip

我们没有更多的变基了。该功能已退出。现在我们有一个具有线性提交历史的分离头。让我们检查一下我们是否成功地重建了历史记录,但保持文件不变。

git diff origin/master

最后的差异显示您的文件没有任何变化,只有历史记录。 这会产生以下历史记录:

$ git log --oneline --graph
* e8eec78 Removed a gitignore specifier from the .gitignore file
* 2d51522 Added 'Lecture 26 Files'
* 93f6908 Added 'Lecture 25 Tuples'
* 2b3d9c5 Added 'Lecture 23 Dictionaries'
* a8bcfaa Reorganized/Fixed all of the code/comments on all of the lectures that I have done up to this point
* f3d0448 Added 'Lecture 21 Lists'
* 7ce1af4 Added 'Lecture 19 Print Formatting'
* 740f459 Changed the numbering of the files
* da6f679 Added 'Lecture 16 Strings'
* 2d4abf6 Reorganized the repository
* 1d88453 Added 'Remove Numbers v.1.py'
* 85cda36 Added 'Lecture 14 Numbers'
* 3d89d1a Deleted an unneeded folder
* bc41dc6 Rename backup final ftp.py to backup ftp v.4 (final).py
* 52a1354 Renamed some of the files
* 0fa9983 Everything is in working order
* dfc9747 Fixed a few if statements
* e183900 Added Countdown Timers and other help to the portfolio
* 2377980 Removed some unnecessary lines of code
* 4172115 Added some new fetures to the script
* 4a7f2d1 Fixed some minor bugs in the code
* 589251c Removed text from a variable
* 93e9742 Finished the backup final ftp script for now
* c5687a3 Added the feature to remove files/folders that are older than a certain age
* 19a495f Removed some blank lines at the bottom of the file
* c2c58c3 Converts the folder to a .tar.bz2 and then deletes the folder
* 6718968 Made some minor changes to the code to increase usability
* b7d6608 Initial commit

注意到提交哈希值发生了怎样的变化?这是因为历史已经改变了。如果你想将它传播回你的 origin/master,你需要强制它。这是因为如果历史哈希值不匹配,推送就会失败,而我们只是更改了大部分历史哈希值。

如果您想将这些更改传播到上游,请执行 git push --force origin/master

请记住,如果 public 面向,其他人可能会分叉您的遥控器,如果其他人可以访问这些提交,最好不要更改 git 历史记录。

$ git --version
git version 2.9.0