I'm using Git for a long time, but recently faced with the interesting trick that allow you revert the file changes history during merge. Here is the steps to reproduce is:
I have the git repository with two files and one commit:
$ git branch
* master
$ git log --oneline
80c8d5a Initial commit
$ git log --oneline -- README
80c8d5a Initial commit
$ ls
README conflict_file
I'm creating the new experimental branch and changing README and conflict_file file:
$ checkout -b experiment
Switched to branch 'experiment'
$ vim README
$ vim conflict_file
$ git commit -am "Experimental changes"
[experiment cdbc988] Experimental changes
2 files changed, 2 insertions(+)
$ git log --oneline -- README
cdbc988 Experimental changes
80c8d5a Initial commit
Going back to master branch and edit conflict_file (to have the conflict during merge):
$ git checkout master
Switched to branch 'master'
$ vim conflict_file
$ git commit -am "Master changes"
[master ad8b68e] Master changes
1 file changed, 1 insertion(+)
The status of my repository in the following:
$ git log --oneline --decorate --graph --all
* ad8b68e (HEAD, master) Master changes
| * cdbc988 (experiment) Experimental changes
|/
* 80c8d5a Initial commit
Trying to merge with the experimental branch:
$ git merge experiment
Auto-merging conflict_file
CONFLICT (content): Merge conflict in conflict_file
Automatic merge failed; fix conflicts and then commit the result.
$ git mergetool
<merging conflict in conflict_file>
Here is the trick:
$ git reset HEAD README
Unstaged changes after reset:
M README
$ git commit
[master 909139f] Merge branch 'experiment'
$ git log --oneline -- README
80c8d5a Initial commit
I lost the changes and history of README file that was introduced in experimental branch in Experimental changes commit. Could anybody please comment how it's correlate with the idea that Git know about all the changes? Is that possible to avoid this scenario? It could become a problem in our company, because merge is allowed operation for developers, but they accidentally could remove somebody's changes.
In the Conceptual Overview section, we saw how a feature branch can incorporate upstream changes from main using either git merge or git rebase . Merging is a safe option that preserves the entire history of your repository, while rebasing creates a linear history by moving your feature branch onto the tip of main .
A merge conflict is an event that occurs when Git is unable to automatically resolve differences in code between two commits. When all the changes in the code occur on different lines or in different files, Git will successfully merge commits without your help.
No history has been lost: The change to README
made on the experimental branch is still contained in commit 210fdc1
. That it is not part of the merge commit 909139f
is solely because you explicitly reverted it before finalizing the merge.
You didn’t say what you expected to happen, so I can only guess what exactly surprised you here. I’ll just point out two likely candidates.
A merge commit isn’t limited to modifying just the files touched since the merge base, or even only the files that have conflicting changes. In fact, it can be completely different from all its parents.
“Completely different” of course isn’t what one would recommend, because it would break everyone’s assumptions about what a merge does. However, it can make perfect sense to extend documentation files in a merge commit, and resolving certain merge conflicts may require changing additional files.
When you call git log -- some_path
, a process called history simplification is invoked. As the man page describes it, git log
will try to display only those commits “that are enough to explain how the files that match the specified paths came to be”. In your case, the initial commit is enough to explain the current state of README
(because README
has still, or again, the same content), so it is all that is shown.
You may want to use --full-history
, possibly together with --simplify-merges
, or some other history simplification options. They, as well as the exact rules for including commits (which are more complicated than implied above), are described in the git log
man page, with an extended example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With