Skip to content

Commit 3e31e8e

Browse files
committed
Documentation for fixing conflicts outside of GitButler
1 parent 1ae44af commit 3e31e8e

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Fixing conflicts outside of GitButler
2+
3+
If you have ended up with conflicted commits and GitButler is completely
4+
unresponsive, they can be recovered using plain git commands in the following
5+
manner:
6+
7+
## Consider hopping on a call with one of us.
8+
9+
The resolution steps make use of some advanced git functions, if you are not
10+
comfortable with any of the steps - we are more than happy to walk you through
11+
any recovery processes.
12+
13+
Join our Discord and let us know about your situation. One of us will help you
14+
work through your problem either through text or via a call.
15+
16+
## Backup!
17+
18+
First, make a copy of your entire repo. We don't want to lose any data if we
19+
make a mistake in recovery.
20+
21+
## Make a new branch
22+
23+
Conflicts often come up as part of a cherry pick so we want to re-perform
24+
the rebase manually - resolving any conflicted commits as we go.
25+
26+
I want the commits to sit on top of origin/master, so I'll run the following
27+
commands to make a new and empty branch to re-build the branch on top of:
28+
29+
```
30+
git switch -c reconstruction
31+
git reset --hard origin/master
32+
```
33+
34+
## Looking at the commits
35+
36+
We can now get an idea of what operations we need to perform to reconstruct the
37+
branch.
38+
39+
By running:
40+
41+
```
42+
git log --graph --oneline <original-branch-name>
43+
```
44+
45+
We can see all the commits that are in our branch.
46+
47+
For my branch, it looks as follows:
48+
49+
```
50+
> git log --oneline --graph reimplement-insert-blank-commit
51+
* b1b1bf07d (reimplement-insert-blank-commit) Improvements to rebase engine for better composability
52+
* c8f5b92a0 Rename reword_commit to commit_reword
53+
* e1fc3b9f5 Reimplement insert blank commit
54+
```
55+
56+
We want to work from the bottom of this list to the top.
57+
58+
To get a better idea of the state of a given commit, we can run:
59+
60+
```
61+
git cat-file -p <commit-id>
62+
```
63+
64+
We can identify if the commit is conflicted by the presence of a header that
65+
looks as follows:
66+
67+
```
68+
gitbutler-conflicted <N>
69+
```
70+
71+
## Reconstructing the branch
72+
73+
Depending on the state of a commit and it's parent, there are some different
74+
operations we want to perform to re-perform the rebase.
75+
76+
### If a commit is conflicted
77+
78+
If a commit is conflicted, we want to first look at the tree of the conflicted
79+
commit. We can do that with the following command:
80+
81+
```
82+
git cat-file -p <commit-id>^{tree}
83+
```
84+
85+
For the first commit in my list, that looks like:
86+
87+
```
88+
> git cat-file -p e1fc3b9f5^{tree}
89+
040000 tree 24e291fb0867efec629b933c00aaeaff39365efd .auto-resolution
90+
040000 tree ffde17e2a4d4c045869b300b4ec9027851581e33 .conflict-base-0
91+
100644 blob dca5869dd76a1eeadeba9387ec7f94b318085c7e .conflict-files
92+
040000 tree 3b23a61344b84fa3f7b93b1ca058d24846a31f57 .conflict-side-0
93+
040000 tree b5a91de1f2ce0a248472d03c1701a20289e4d657 .conflict-side-1
94+
100644 blob 2af04b7f1384300b742f6112005cddc5a87be022 README.txt
95+
```
96+
97+
Here we see the conflicted representation of a commit in GitButler.
98+
99+
There are four entries that are relevant here:
100+
101+
- `.auto-resolution` - This contains a resolution attempt that GitButler made
102+
when cherry-picking the commit.
103+
- `.conflict-base-0` - This contains the tree of the commit that was
104+
cherry-picked to produce the conflicted commit.
105+
- `.conflict-side-0` - This contains the tree of the commit that we tried to
106+
cherry-pick onto.
107+
- `.conflict-side-1` - This contains the tree of the origional commit before it
108+
was cherry-picked.
109+
110+
To re-perform the cherry-pick that GitButler was trying to do. We do that by
111+
first making a commit that holds the `.conflict-base-0` tree which can be done
112+
by running:
113+
114+
```
115+
git commit-tree <id-of-conflict-base-0> -p HEAD -m "base"
116+
```
117+
118+
For me, that looks like:
119+
120+
```
121+
> git commit-tree ffde17e2a4d4c045869b300b4ec9027851581e33 -p HEAD -m "base"
122+
0100ea63fe63a2894567de42371f8d6cf79e4a85
123+
```
124+
125+
This has given us an OID in return. This is the object ID of whatever that base
126+
tree contains.
127+
128+
We then want to create a commit that contains the `.conflict-side-1` tree, and
129+
has that new "base" commit as it's parent. We can do that by running:
130+
131+
```
132+
git commit-tree <id-of-conflict-side-1> -p <id-of-base-commit> -m "Desired commit message"
133+
```
134+
135+
For me this looks like:
136+
137+
```
138+
git commit-tree b5a91de1f2ce0a248472d03c1701a20289e4d657 -p 0100ea63fe63a2894567de42371f8d6cf79e4a85 -m "Reimplement insert blank commit"
139+
35d518d2ea68635631593faff34b11e3b1904014
140+
```
141+
142+
Using that returned commit OID, we can then bring that commit on top of our
143+
branch with:
144+
145+
```
146+
git cherry-pick <returned commit id>
147+
```
148+
149+
For me, that looked like:
150+
151+
```
152+
git cherry-pick 35d518d2ea68635631593faff34b11e3b1904014
153+
```
154+
155+
Git may prompt you to solve some conflicts here which you can resolve in the
156+
standard manner.
157+
158+
### If a commit is **not conflicted**, but has a **conflicted parent**.
159+
160+
If the commit is not conflicted, but the commit before it in your log WAS
161+
conflicted, then we similarly need to create a commit to cherry-pick on our own.
162+
163+
First, you will want to take a look at that parent's commit tree with:
164+
165+
```
166+
git cat-file -p <parent-commit-oid>
167+
```
168+
169+
We want to make a base commit that uses the `.auto-resolution` tree. We can do
170+
that with:
171+
172+
```
173+
git commit-tree <id-of-auto-resolution-tree> -p HEAD -m "Desired commit message"
174+
```
175+
176+
We then want to make a commit that has the tree of the non-conflicted commit,
177+
with the parent as the base commit we just made.
178+
179+
We can first find the tree of the non-conflicted commit by running:
180+
181+
```
182+
git cat-file -p <unconflicted-commit-id>
183+
```
184+
185+
and copying the entry after `tree`.
186+
187+
We then want to make our commit to cherry pick with:
188+
189+
```
190+
git commit-tree <id-of-unconflicted-commit> -p <id-of-base-commit> -m "desired commit message"
191+
```
192+
193+
We can then cherry-pick that commit with `git cherry-pick` onto our branch,
194+
following the standard conflict flow if applicable.
195+
196+
### If the commit is **not conflicted** and its parent is **not conflicted**
197+
198+
If this is the case, we can run the standard `git cherry-pick` command to bring
199+
that commit into our reconstruction branch, following the standard conflict flow
200+
if applicable.
201+
202+
## Pushing your reconstructed branch
203+
204+
Once you have finished bringing all of your commits into your reconstruction
205+
branch, you can then push it to your remote via `git push`.

0 commit comments

Comments
 (0)