Reputation: 4667
I have a branch in a Github repo with a name like this: feature/X/mybranch
. A colleague has made changes to my branch, but committed them to feature/x/mybranch
. Github, being seemingly case-sensitive, made a separate branch with his commit.
The issue now is that my Git client only sees one branch (I am on macOS), the original one with upper case. This gives all sorts of issues. Initially, I couldn't even see his commit, and without knowing what the real issue was, I tried different things and I was finally able to get his changes after a git reset --hard
. However some side effects are still present. For instance, my client keeps telling me I have commits that haven't been pushed, even though I can see them in Github.
Ideally I just want to merge his branch into my and delete it (or even just delete since I am pretty sure I have all his changes), but I have no idea how to do that. As mentioned, my client (tried both in terminal and Sourcetree) only sees one branch, and I don't really know what would happen if I delete that.
Upvotes: 5
Views: 4295
Reputation: 27036
If you have two branches which are named identical but differ in the case only (e.g. DEVELOP/mybranch
and develop/mybranch
), both are stored but
some IDE's (such as Pycharm) and source control tools like SourceTree will not recognize 2 branches, they will only show one of them - so you need to resolve this by making their names unique again. Typically you only want to keep one of them and remove the other one created accidently.
Since you can see both branches in the GitHub web interface (https://github.com/your-org/the-project
), you can directly fix the issue right there:
master
(to make sure you're not on any of these branches)<> Code
tabMaster
there is a link button nn Branches
(nn = number of branches). Click on itfeature/x/mybranch
and feature/X/mybranch
feature/x/mybranch
is newer (requires steps 4. and 5.)feature/X/mybranch
is older (for example - if feature/X/mybranch
is 18 behind and 0 ahead, but feature/x/mybranch
is 0 behind and 5 ahead of master, then feature/x/mybranch
is newer - and you want to rename1) the older branch)feature/X/mybranch
to have a unique non-case dependant name by clicking on the ...
and select rename branch
, e.g. change the name to tmp_old_feature/x/mybranch
feature/X/mybranch
is newer (requires steps 4. - 7.)For both branches check "behind" and "ahead" columns to determine which one is newer. Going forward, let's say feature/X/mybranch
is newer (for example - if feature/x/mybranch
is 18 behind and 0 ahead, but feature/X/mybranch
is 0 behind and 5 ahead of master, then feature/X/mybranch
is newer - you want to keep this branch but need to rename1) it too
Rename the newer branch feature/X/mybranch
to have a unique non-case dependant name by clicking on the ...
and select rename branch
, e.g. change the name to tmp_new_feature/x/mybranch
Rename the older branch feature/x/mybranch
to tmp_old_feature/x/mybranch
Rename the tmp_new_feature/x/mybranch
branch to feature/x/mybranch
(which is the name you want to work with)
Now you can continue with your work on feature/x/mybranch
and you have a copy of the older branch (tmp_old_feature/x/mybranch
).
And remember to use a consistent naming schema for the branches, so this cannot happen again (for example, I am using only lowercase letters for the branch naming - of course you can do that differently, but it needs to be consistent within your team).
1) To rename a branch: click on the ...
beneath it and select rename branch
, then change its name
Upvotes: 1
Reputation: 490078
There are several interlocking problems, all of which stem from a single issue: macOS file systems default to case-folding, so that a file named README
can be opened using the name readme
, and vice versa.
Git sometimes stores branch name-and-value sets in a single file (.git/packed-refs
), and when it does so, the names are case-sensitive, so that feature/X/mybranch
and feature/x/mybranch
are unrelated branch names. But Git sometimes stores the name as a file name (in/for which the slashes become folder name delimiters), with the hash ID contained in that file, and here, any attempt to use feature/X
as if it were separate from feature/x
fails, so that you end up with just one file named mybranch
in a folder whose name is either x
or X
.
The easiest way to fix it, by far, is to work within Git on a case-sensitive file system. For instance, if you have a Linux machine—or virtual machine—you spin up that Linux system, clone the GitHub repository, and now everything Just Works and you have the two different branch names and can fix everything easily, update GitHub, delete the undesired name, and so on. This also covers all the file-name-within-a-commit issues since you can now have two different files whose names are README
and readme
.
You don't need to use a separate VM, though, because macOS allows you to create a case-sensitive disk image and mount it. You can then do your work in this mounted volume. This solves most of the problems; the remaining ones are decomposed vs composed Unicode (two different ways to name a file agréable
for instance), which Linux allows but macOS still forbids.
To create a case-sensitive disk image, see my previous answer to a different question. This covers many more situations than your immediate one.
Given your immediate situation, though, there's a simple and direct way to do this without fussing with a Linux VM or case-sensitive file system, by doing most of the work on GitHub itself. It's a little bit tricky as you need to make sure you have the right commits available locally, but a git fetch origin
gets them. You then need to use the FETCH_HEAD
file that git fetch
writes—in .git/FETCH_HEAD
—to extract particular hash IDs.
The contents of .git/FETCH_HEAD
are mostly self-explanatory. It contains the branch name as seen on the other Git, and the hash ID (plus some other stuff): one entry per line, on multiple lines, corresponding to the branch names in that other Git.
From your own Git, you can then:
git push origin <hash-id>:<good-name>
git push --delete origin <bad-name>
to the Git at GitHub. The first command—which may require --force
in some cases (if it does, be careful here, and consider using --force-with-lease=refname:hash:
)—will create or update the desired branch name with the desired casing, using the fact that GitHub itself has case-sensitivity. So you now have the "right" branch name available there, set to the right hash ID. The second command will delete the name with the undesired casing.
You may also want to use git branch -r -d
to delete the remote-tracking name, if it has the wrong case:
git branch -r -d <bad-name>
Your own Git can now deal with the Git repository over on GitHub because it has only the good name to deal with, so now:
git fetch origin
behaves well, and does what you need.
(None of the above is tested; there could be typos.)
Upvotes: 3
Reputation: 1329692
Create a temporary branch on top of your current branch and switch to it
git switch tmp
From there, you can safely delete your local branches
git branch -d feature/x/mybranch
git branch -d feature/X/mybranch
(you might have to use -D
if git protests the branch is not fully merged to its upstream branch)
Finally, recreate your branch with the right case:
git switch feature/X/mybranch
Upvotes: 2